2014-11-11 2 views
3

Рассмотрим следующий тип POD класса:реализации ISerializable для контроля версий

public class Price { public decimal OfferPrice { get; set; } } 

объекты этого класса извлекаются с сервера, так что давайте украсить его сериализуемого

[Serializable] 
public class Price { public decimal OfferPrice { get; set; } } 

Теперь есть два клиента на различные машины получают эти объекты. Они не будут отправлять цены. Все они получают копию сборки Price.

Теперь класс расширен с помощью BonusPrice.

[Serializable] 
public class Price { 
    public decimal OfferPrice { get; set; } 
    public decimal BonusPrice { get; set; } 
} 

Новая сборка развернута на сервере, одному из клиентов, но НЕ другому. Таким образом, старый клиент с версией будет сбой при (де) сериализации объектов Price.

Клиент со старой версией не нуждается в поле BonusPrice, поэтому было бы неплохо, что он продолжает работать, когда есть разница в версии. Поэтому я имею в виду реализации ISerializable с самого начала, так что первая и вторая версия будет выглядеть так:

// version 1.0 
[Serializable] 
public class Price : ISerializable { 
    protected Price(SerializationInfo info, StreamingContext context) { 
    OfferPrice = info.GetDecimal("op"); 
    } 

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] 
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { 
    info.AddValue("op", OfferPrice); 
    } 
} 

// version 2.0 
[Serializable] 
public class Price : ISerializable { 
    protected Price(SerializationInfo info, StreamingContext context) { 
    OfferPrice = info.GetDecimal("op"); 
    BonusPrice = info.GetDecimal("bp"); 
    } 

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] 
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { 
    info.AddValue("op", OfferPrice); 
    info.AddValue("bp", BonusPrice); 
    } 
} 

Так что теперь, когда один клиент не обновляется до версии 2 он будет по-прежнему держать на десериализации только OfferPrice и не сбой. Когда он будет обновлен в какой-то момент, он автоматически использует BonusPrice.

Мой вопрос: реализует ISerializable хороший способ управления версиями при чтении объектов? Как обычно решаются эти проблемы?

+0

Хороший вопрос. Как я уже упоминал в своем ответе, что вы можете использовать 'OptionalFieldAttribute', я никогда не использовал его, потому что было слишком поздно, когда я узнал что-то подобное. FWIW Я использовал 'ISerializable' только для управления версиями в моих проектах. –

ответ

2

Вы можете использовать OptionalFieldAttribute для управления версиями BinaryFormatter и SoapFormatter.

OptionalFieldAttribute имеет VersionAdded недвижимость. В версии 2.0 .NET Framework это не используется. Тем не менее, важно правильно установить это свойство, чтобы убедиться, что тип будет совместим с будущими механизмами сериализации.

Свойство указывает, какая версия данного типа задана в поле . Он должен быть увеличен ровно один (начиная с 2) каждого время типа модифицированного

Также есть и другие способы, как сериализации колбек, SerializationBinder, ISerializable и т.д ..

См Version Tolerant Serialization для получения дополнительной информации.

+0

эта конечно легче.Таким образом, CLR не сериализует эти поля, если он не может найти их с отражением, а doe не выдает исключения? – Laurijssen

+0

@ ServéLaurijssen Да, сериализаторы не будут генерировать исключение (оно просто игнорируется), когда данные отсутствуют, и наоборот. –

+0

al right спасибо! Я не знал о OptionalField – Laurijssen

1

С моей точки зрения вы пытаетесь смешивать две версии протоколов в одном контракте. В вашем примере это работает, но на практике часто сложно объединить новый протокол, поэтому лучше оставить его отдельным. Другими словами, ваш сервер должен поддерживать обе версии самостоятельно. Посмотрите на OData Protocol Versioning