DataContract с изменением наследования

Я использую DataContracts для сериализации объектов. Предположим, я сериализовал данные, структурированные таким образом:

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

    [DataMember]
    public string name;

    ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; }
}

Теперь я меняю свою архитектуру, и я хотел бы прочитать ранее сериализованные данные с помощью этих классов:

[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;
}

но я получаю name = null. Я знаю, что это зависит от порядка: сначала файл был сохранен с возрастом, а затем прочитан, начиная с имени, потому что он находится в базовом классе.
Есть ли способ справиться с этим, может быть, изменив порядок?


person Maurizio Reginelli    schedule 30.05.2012    source источник
comment
Виртуальное предложение сработало?   -  person M Afifi    schedule 31.05.2012


Ответы (2)


Я не думаю, что это возможно.

В прошлом XML был бы

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

Ожидается

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

Свойство находится выше во всем, что сериализуется в новом DataContract. Изменение иерархии наследования является критическим изменением с помощью метода IExtensibleDataObject.

Использование наследования вместе с контрактами данных разрешено при условии, что наследование не используется в качестве механизма управления версиями и соблюдаются определенные правила. Если тип является производным от определенного базового типа, не делайте его производным от другого базового типа в будущей версии (если у него нет того же контракта данных). Есть одно исключение: вы можете вставить тип в иерархию между типом контракта данных и его базовым типом, но только если он не содержит членов данных с теми же именами, что и другие члены в любых возможных версиях других типов в иерархия. Как правило, использование членов данных с одинаковыми именами на разных уровнях одной и той же иерархии наследования может привести к серьезным проблемам с версиями, и этого следует избегать.

Дополнительные сведения см. в разделе Рекомендации: управление версиями контрактов данных.

Редактировать 1:

Возможно, вы могли бы попробовать сделать имя виртуальным в Animal и переопределить его в Dog? Или какой-то сумасшедший метод заставить сериализованную новую версию иметь имя под собакой. то есть что-то вроде,

[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; 
} 
person M Afifi    schedule 30.05.2012

Вам следует взглянуть на Управление версиями контракта WCF, обсуждаемое в этом сообщении SO.

По сути, вам нужно назначить Namespace на ваш ServiceContract и сохраните как новую, так и старую версии вокруг, если вам нужна обратная совместимость по мере развития вашего контракта.

person SliverNinja - MSFT    schedule 30.05.2012
comment
@silverninja Мне это нравится, ссылаясь на мой собственный вопрос;) - person M Afifi; 30.05.2012
comment
Потрясающе... Я не уловил этого! Я прочитал его вчера и оценил вашу недавнюю публикацию. Управление версиями WCF — это то, с чем мы всегда сталкивались, но никогда не использовали Namespaces. - person SliverNinja - MSFT; 30.05.2012