Search code examples
c#.netwcfdatacontract

DataContract with inheritance change


I'm using DataContracts to serialize objects. Suppose I have serialized a data structured in this way:

[DataContract]
public class Dog : IExtensibleDataObject
{
    [DataMember]
    public int age;

    [DataMember]
    public string name;

    ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; }
}

Now I'm changing my architecture and I would like to read the previously serialized data with this classes:

[DataContract]
[KnownType(typeof(Dog))]
public class Animal : IExtensibleDataObject
{
    [DataMember]
    public string name;

    ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; }
}

[DataContract]
public class Dog : Animal
{
    [DataMember]
    public int age;
}

but I obtain name = null. I know that this depends on the order: the file was saved with age for first and then read starting from name, because it is on the base class.
Is there a way to handle this, maybe by changing the order?


Solution

  • I don't think that's possible.

    The xml in the past would have been

    <dog>
        <name>Bob</name>
        <age>10</age>
    </dog>
    

    Its now expecting

    <animal>
        <name>Bob</name>
        <dog>
            <age>10</age>
        </dog>
    </animal>
    

    The property is higher up in anything that's serialized on the new DataContract. Changing inheritance heirarchy is a breaking change with the IExtensibleDataObject method.

    The use of inheritance together with data contracts is allowed, provided that inheritance is not used as a versioning mechanism and that certain rules are followed. If a type derives from a certain base type, do not make it derive from a different base type in a future version (unless it has the same data contract). There is one exception to this: you can insert a type into the hierarchy between a data contract type and its base type, but only if it does not contain data members with the same names as other members in any possible versions of the other types in the hierarchy. In general, using data members with the same names at different levels of the same inheritance hierarchy can lead to serious versioning problems and should be avoided.

    More at Best Practices: Data Contract Versioning

    Edit 1:

    You could perhaps try making Name virtual in Animal and overriding it in Dog? Or some crazy method to force the serialized new version to have name under dog. i.e. something like,

    [DataContract] 
    [KnownType(typeof(Dog))] 
    public class Animal : IExtensibleDataObject 
    {
        public virtual string name; 
    
        ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; } 
    } 
    
    [DataContract] 
    public class Dog : Animal 
    { 
        [DataMember] 
        public override string name; 
    
        [DataMember] 
        public int age; 
    }