Search code examples
c#xmlserialization

c# XML Serialization: Order of namespace declarations


I have a very odd situation. I serialize my namespaces like this:

var namespaces = new XmlSerializerNamespaces();
namespaces.Add("xsd", "http://www.w3.org/2001/XMLSchema");
namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

serializer.Serialize(writer, config, namespaces);

On my machine I get the following xml (one line I just added linebreaks):

<SystemConfiguration 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns="http://www.schaeffler.com/sara/systemconfiguration/">

On the buildserver I get with the same software this:

<SystemConfiguration 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns="http://www.schaeffler.com/sara/systemconfiguration/">

You see the order of xsd and xsi is swapped. I checked the implementation of the serializer and saw that the order is determined with a hashtable and there is not interface for XmlSerializerNamespaces to implement my own serializer for the namespaces.

This is the method in XmlSerializationWriter:

protected void WriteNamespaceDeclarations(XmlSerializerNamespaces xmlns)
    {
      if (xmlns != null)
      {
        foreach (DictionaryEntry dictionaryEntry in xmlns.Namespaces)
        {
          string localName = (string) dictionaryEntry.Key;
          string ns = (string) dictionaryEntry.Value;
          if (this.namespaces != null)
          {
            string str = this.namespaces.Namespaces[(object) localName] as string;
            if (str != null && str != ns)
              throw new InvalidOperationException(Res.GetString("XmlDuplicateNs", (object) localName, (object) ns));
          }
          string str1 = ns == null || ns.Length == 0 ? (string) null : this.Writer.LookupPrefix(ns);
          if (str1 == null || str1 != localName)
            this.WriteAttribute("xmlns", localName, (string) null, ns);
        }
      }
      this.namespaces = (XmlSerializerNamespaces) null;
    }

What can cause the different order of the namespaces within the hashmap?


Solution

  • From msdn:

    The elements are sorted according to the hash value of the key, and each key can exist only once in the collection.

    The hash value for DictionaryEntry (a struct) is extracted from ValueType.GetHashCode(). It is likely returning an in-determinable key - potentially based upon the underlying reference value. You would need to do some further reflection to find out for certain how the hash is being calculated. It may just be using the default object implementation.

    Also from msdn:

    A hash code is intended for efficient insertion and lookup in collections that are based on a hash table. A hash code is not a permanent value.