Сериализация и управление версиями

Я должен сериализировать некоторые данные для строкового представления. Строка затем хранится в DB в специальном столбце SerializeData.

Я создал специальные классы, которые используются для сериализации.

[Serializable]
public class SerializableContingentOrder
{
    public Guid SomeGuidData { get; set; }
    public decimal SomeDecimalData { get; set; }
    public MyEnumerationType1 EnumData1 { get; set; }
}

Сериализация:

protected override string Serialize()
{
    SerializableContingentOrder sco = new SerializableContingentOrder(this);

    MemoryStream ms = new MemoryStream();
    SoapFormatter sf = new SoapFormatter();
    sf.Serialize(ms, sco);
    string data = Convert.ToBase64String(ms.ToArray());
    ms.Close();
    return data;
}

Десериализация:

protected override bool Deserialize(string data)
{
    MemoryStream ms = new MemoryStream(Convert.FromBase64String(data).ToArray());
    SoapFormatter sf = new SoapFormatter();

    SerializableContingentOrder sco = sf.Deserialize(ms) as SerializableContingentOrder;
    ms.Close();
    return true;
}

Теперь я хочу иметь поддержку управления версиями. Что происходит, если я изменяюсь SerializableContingentOrder класс. Я хочу смочь добавить новые поля в будущем.

Я должен переключиться на сериализацию DataContract? Дайте мне короткий отрывок?

5
задан João Angelo 6 July 2010 в 10:22
поделиться

4 ответа

Я решительно сторонник против хранения данных BinaryFormatter или SoapFormatter в базе данных; это:

  • хрупкий
  • не устойчивый к версиям
  • не независимый от платформы

BinaryFormatter подходит для передачи данных между сборками .NET (при нажатии), но я бы порекомендовал более предсказуемый сериализатор. DataContractSerializer - это вариант (как JSON или XmlSerializer ), но я не буду использовать NetDataContractSerializer для всех по тем же причинам, что и выше. У меня возникнет соблазн использовать protobuf-net, поскольку это эффективный двоичный файл в известном эффективном формате, независимый от платформы и устойчивый к версиям!

Например:

[DataContract]
public class SerializableContingentOrder
{
    [DataMember(Order=1)] public Guid SomeGuidData { get; set; }
    [DataMember(Order=2)] public decimal SomeDecimalData { get; set; }
    [DataMember(Order=3)] public MyEnumerationType1 EnumData1 { get; set; }
}

Сериализация:

protected override string Serialize()
{
    SerializableContingentOrder sco = new SerializableContingentOrder(this);   
    using(MemoryStream ms = new MemoryStream()) {
        Serializer.Serialize(ms, sco);
        return Convert.ToBase64String(ms.ToArray());
    }
}

Десериализация:

protected override bool Deserialize(string data)
{
    using(MemoryStream ms = new MemoryStream(Convert.FromBase64String(data)) {
        SerializableContingentOrder sco =
               Serializer.Deserialize<SerializableContingentOrder>(ms)
    }
    return true;
}
11
ответ дан 18 December 2019 в 06:49
поделиться

Начиная с .NET 2.0 у вас есть поддержка сериализации, допускающей версии, если вы используете BinaryFormatter . SoapFormatter также поддерживает некоторые функции, устойчивые к версиям, но не все функции, поддерживаемые BinaryFormatter , в частности, не поддерживается устойчивость к посторонним данным.

Для получения дополнительной информации проверьте:

Сериализация, допускающая версии

3
ответ дан 18 December 2019 в 06:49
поделиться

У вас есть два варианта, если вы хотите поддерживать управление версиями. Используйте DataContracts или сериализацию, устойчивую к версиям. Оба действительны.

DataContacts обрабатывает добавление и удаление полей автоматически. См. Управление версиями контактов данных и Рекомендации: Управление версиями контрактов данных для получения дополнительной информации.

Пример DataContact

[DataContract]
public class ContingentOrder
{
    [DataMember(Order=1)]
    public Guid TriggerDealAssetID;

    [DataMember(Order=2)]
    public decimal TriggerPrice;

    [DataMember(Order=3)]
    public TriggerPriceTypes TriggerPriceType;

    [DataMember(Order=4)]
    public PriceTriggeringConditions PriceTriggeringCondition;

}

Пример сериализации, устойчивой к версиям

// Version 1
[Serializable]
public class SerializableContingentOrder
{
    public Guid TriggerDealAssetID;
    public decimal TriggerPrice;
    public TriggerPriceTypes TriggerPriceType;
    // Omitted PriceTriggeringCondition as an example
}

// Version 2 
[Serializable]
public class SerializableContingentOrder
{
    public Guid TriggerDealAssetID;
    public decimal TriggerPrice;
    public TriggerPriceTypes TriggerPriceType;

    [OptionalField(VersionAdded = 2)]
    public PriceTriggeringConditions PriceTriggeringCondition;

    [OnDeserializing]
    void SetCountryRegionDefault (StreamingContext sc)
    {
        PriceTriggeringCondition = /* DEFAULT VALUE */;
    }

}

Дополнительная информация о сериализации, допускающей версии (ссылка не работает). Особенно обратите внимание на передовой опыт внизу страницы.

Обратите внимание, что DataContracts были введены в .NET 3.5, поэтому у вас может не быть этой опции, если вам нужно ориентироваться на .NET 2.0.

HTH,

7
ответ дан 18 December 2019 в 06:49
поделиться

Самый простой способ - украсить новые поля атрибутом OptionalFieldAttribute . Это не идеально, но может подойти в вашем случае.

2
ответ дан 18 December 2019 в 06:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: