Какой сериализатор больше всего прощает изменения сериализованных типов в .NET? - PullRequest
0 голосов
/ 21 октября 2009

Я заметил, что XmlSerializer более прост в добавлении новых членов, удалении существующих и т. Д. В сериализованные типы.

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

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

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

Ответы [ 6 ]

4 голосов
/ 21 октября 2009

Вы упомянули двоичный файл, и действительно BinaryFormatter очень хрупкий здесь. Проблема в том, что 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;}

    // ...
}

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

2 голосов
/ 21 октября 2009

Вы можете унаследовать свой класс от 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 голосов
/ 21 октября 2009

Также можно посмотреть 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;
}
0 голосов
/ 21 октября 2009

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

Смотрите пост ниже:

Сериализация и десериализация в файл XML, C #

0 голосов
/ 21 октября 2009

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

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

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

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

    [Serializable]
    public class data
    {
      private int m_MyInteger;
      // New field
      private double m_MyDouble;

      [OnDeserializing]
      internal void OnDeserializing(StreamingContext context)
      {
        // some good default value
        m_MyDouble = 5;
      }

      public int MyInteger
      {
        get{ return m_MyInteger; }
        set { m_MyInteger = value; }
      }
   }
0 голосов
/ 21 октября 2009

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

...