2009-10-21 2 views
0

Я заметил, что XmlSerializer более прощает добавление новых членов, удаление существующих и т. Д. Для сериализованных типов.Какой сериализатор наиболее прост для изменения сериализованных типов в .NET?

Когда я сделал это с помощью BinaryFormatter и попытался десериализовать старые данные, он сделал исключение.

Какие еще альтернативы существуют для вариантов прощения, то есть тот, который не генерирует исключение, просто использует значения по умолчанию, пропускает их и т. Д.?

Являются ли протокольные буферы прощающими в этом отношении?

ответ

2

Вы можете наследовать свой класс от ISerializable и определить пользовательскую GetObjectData. Я не тестировал это, но такой класс может быть десериализуем из двоичного формата, даже если с тех пор были внесены изменения в класс.

EDIT

Я только что подтвердил, что это работает. Вы можете использовать код, подобный приведенному ниже примеру, для явного определения того, как объект сериализуется и десериализован. Тогда вам решать, как эти методы работают со старыми версиями вашего класса. Я проверил это путем сериализации экземпляра Cereal в двоичном файле, затем внесения изменений в класс и чтения файла для десериализации.

[Serializable] 
private class Cereal : ISerializable 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public Cereal() 
    { 
    } 

    protected Cereal(SerializationInfo info, StreamingContext context) 
    { 
     Id = info.GetInt32 ("Id"); 
     Name = info.GetString ("Name"); 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue ("Id", Id); 
     info.AddValue ("Name", Name); 
    } 
} 
+0

Да, это именно та причина, по которой существует ISerializable, поэтому вы можете иметь дело с предыдущими форматами. –

0

Я настоятельно рекомендую сделать свою сериализацию так, чтобы у вас были четко определенные форматы файлов, не зависящие от языковых схем.

4

Вы упомянули двоичный код, и действительно BinaryFormatter здесь very brittle. Проблема заключается в том, что BinaryFormatter является типом и полем. Вместо этого, вы хотите контракт на основе сериалайзера, такие как XmlSerialzier, DataContractSerializer (3.0) и т.д.

Или двоичный, protobuf-net является C# реализации «буфера протокола» формат проволока Google, но повторно реализованы по .NET линии; (заметьте: я автор ...).

Это (как и другие) основанный на данных контракт, но вместо <CustomerName>asdasd</CustomerName> и т. Д. Он использует числовые теги для определения вещей; так:

[ProtoContract] 
public class Customer { 
    [ProtoMember(1)] 
    public string Name {get;set;} 

    // ... 
} 

Поскольку вы добавляете больше членов, вы даете им новые уникальные номера; это позволяет расширять его, не полагаясь на какие-либо имена и т. д. Плюс это очень быстро; -p Как и в случае с XmlSerializer, он будет игнорировать то, чего он не ожидает (или может хранить их для безопасного округления неожиданных данных), и поддерживает те же самые вещи по умолчанию. Вы даже можете использовать существующий XML атрибуты:

[XmlType] 
public class Customer { 
    [XmlElement(Order=1)] 
    public string Name {get;set;} 

    // ... 
} 

я мог бы говорить об этом предмете в течение всего дня, так что я лучше заткнись, прежде чем [слишком поздно].

+0

Спасибо, Марк, пожалуйста, не стесняйтесь говорить больше :) Одна вещь, которую я задаюсь вопросом, если вы говорите, что вы меняете тип и добавляете новые уникальные номера, можете ли вы избавиться от старых чисел позже? Например, если вы использовали 1,2,3,4 и теперь 5 для нового члена, который заменяет 2. Можете ли вы позже получить 2, чтобы представить 5? Я просто подумал, что это может быть чище для моей цели? –

+1

Я узнал две вещи из этого комментария. вы британцы, и вполне уверен в себе. : D – Letterman

+0

lol, вы имеете в виду Marc right? –

0

Я на самом деле нахожу, что бинарный форматтер является самым долговечным в долгосрочной перспективе.

Обеспечивает отличную совместимость в прямом направлении. То есть, если вы обновите файл до новой версии, он не будет работать со старым десериализатором.

Обычно я создаю несколько простых классов данных, которые я хочу использовать для сериализации. Когда мне нужно изменить класс, я реализую методы OnDeserialized/OnDeserializing. Это позволяет обновлять данные.

Бинарный форматтер не требует, чтобы у вас был публичный сеттер для ваших свойств, что для меня иногда является большой проблемой.

0

Думаю, следующее сообщение может вам помочь. Я также согласен с другими, которые сказали написать собственный сериализатор. Это лучше, чем сгенерированный код из xsd.exe.

Смотрите ниже сообщение:

Serialization and Deserialization into an XML file, C#

0

Вы также можете посмотреть на OptionalFieldAttribute для использования с SerializableAttribute/NonSerializedAttribute и BinaryFormatter и SoapFormatter

... версия 1

[Serializable] 
public class MyClass 
{ 
    public string field1; 

    [NonSerialized] 
    public string field2; 
} 

... версия 2

[Serializable] 
public class MyClass 
{   
    public string field1; 

    [NonSerialized] 
    public string field2; 

    [OptionalField] 
    public string field3; 
}