Resolving Conflicts in Serialization

DataContractSerializer supports multiple serialization mechanisms. If more than one serialization mechanism is specified for the same type, which one gets used?

Experimentation is the easiest way to figure out what happens. I'll look at different combinations of the XML serializer, the data contract serializer, and the "collection-based" data contract serializer, which is the default mechanism for the concrete collection classes.

Let's start with a base interface that defines a member for the type.

 public interface IFoo
{
   string data { get; set; }
}

Now, let's apply various combinations of serialization mechanisms to implementations of the base interface. I'll start with each of the serializers by themselves and then each of the legal combinations. Data contracts and collection data contracts can't be used at the same time so that pairing isn't possible as well as trying to use all three serialization mechanisms at once.

Here's a quick test program to run through the combinations.

 public class Program
{
   [DataContract]
   public class FooDataContract : IFoo
   {
      [DataMember]
      public string data { get; set; }
   }

   [Serializable]
   public class FooSerializable : IFoo
   {
      public string data { get; set; }
   }

   [CollectionDataContract]
   public class FooCollection : List<int>, IFoo
   {
      [DataMember]
      public string data { get; set; }
   }

   [Serializable]
   [DataContract]
   public class FooSerializableDataContract : IFoo
   {
      [DataMember]
      public string data { get; set; }
   }

   [Serializable]
   [CollectionDataContract]
   public class FooSerializableCollection : List<int>, IFoo
   {
      [DataMember]
      public string data { get; set; }
   }

   static void Main(string[] args)
   {
      using (XmlTextWriter writer = new XmlTextWriter(Console.Out))
      {
         foreach (Type type in typeof(Program).GetNestedTypes())
         {
            IFoo foo = (IFoo)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
            foo.data = type.Name;
            DataContractSerializer serializer = new DataContractSerializer(type);
            writer.WriteString(type.Name);
            writer.WriteWhitespace("\n");
            serializer.WriteObject(writer, foo);
            writer.WriteWhitespace("\n\n");
         }
      }
      Console.ReadLine();
   }
}

That gives us a set of outputs to inspect to see what serializer won.

FooDataContract

<Program.FooDataContract xmlns:i="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://schemas.datacontract.org/2004/07/"><data>FooDataContract</data></Program.FooDataContract>

FooSerializable

<Program.FooSerializable xmlns:i="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://schemas.datacontract.org/2004/07/"><_x003C_data_x003E_k__BackingField>FooSerializable</_x003C_data_x003E_k__BackingField></Program.FooSerializable>

FooCollection

<Program.FooCollection xmlns:i="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://schemas.datacontract.org/2004/07/" />

FooSerializableDataContract

<Program.FooSerializableDataContract xmlns:i="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://schemas.datacontract.org/2004/07/"><data>FooSerializableDataContract</data></Program.FooSerializableDataContract>

FooSerializableCollection

<Program.FooSerializableCollection xmlns:i="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://schemas.datacontract.org/2004/07/" />

  • FooDataContract gave us the data member with the nice format for properties.
  • FooSerializable gave us the data member with the ugly format for properties.
  • FooCollection failed to give us the data member (CollectionDataContract doesn't let you have non-default members).
  • FooSerializableDataContract is the same as FooDataContract. DataContract beats Serializable.
  • FooSerializableCollection is the same as FooCollection. CollectionDataContract beats Serializable as well.

Next time: TCP Keep Alive