Я должен сериализировать некоторые данные для строкового представления. Строка затем хранится в 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? Дайте мне короткий отрывок?
Я решительно сторонник против хранения данных 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;
}
Начиная с .NET 2.0 у вас есть поддержка сериализации, допускающей версии, если вы используете BinaryFormatter
. SoapFormatter
также поддерживает некоторые функции, устойчивые к версиям, но не все функции, поддерживаемые BinaryFormatter
, в частности, не поддерживается устойчивость к посторонним данным.
Для получения дополнительной информации проверьте:
У вас есть два варианта, если вы хотите поддерживать управление версиями. Используйте 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,
Самый простой способ - украсить новые поля атрибутом OptionalFieldAttribute
. Это не идеально, но может подойти в вашем случае.