[英]DataContract backward compatibility of serialization
I have had a class like that: 我有一个这样的课:
[DataContract(Namespace = "blah")]
public class Item
{
[DataMember(Order = 0)]
public int Index { get; set; }
[DataMember(Order = 1)]
public Uri ItemSource { get; set; }
[DataMember(Order = 2)]
public Uri ErrorSource { get; set; }
}
And I have a lot of serialized copies (in files) of it (including some files on production), now I have the task to change this class to the following: 我有很多序列化副本(在文件中)(包括生产中的一些文件),现在我有把这个类更改为以下内容的任务:
[DataContract(Namespace = "blah")]
public class Item
{
[DataMember(Order = 0)]
public int Index { get; set; }
[DataMember(Order = 1)]
public ItemSourcesCollection Sources { get; set; }
}
where ItemSourcesCollection is 其中ItemSourcesCollection是
[CollectionDataContract(ItemName = "ItemSourceItem", Namespace = "blah")]
public class ItemSourcesCollection : List<ItemSource> {}
where ItemSource is 其中ItemSource是
[DataContract]
public class ItemSource
{
[DataMember]
public Uri SourcePath { get; set; }
[DataMember]
public ItemSourceType Type { get; set; }
}
where ItemSourceType is 其中ItemSourceType是
[Serializable]
public enum ItemSourceType
{
Data,
Errors
}
The problem is a backward compatibility. 问题是向后兼容性。 Is it possible that old serialized items were deserialized correctly?
是否有可能正确反序列化旧的序列化项目? What are the best practices/patterns of migrating the data contracts with backward compatibility?
通过向后兼容性迁移数据合同的最佳实践/模式是什么?
Yes it is possible with some reflection. 是的,有可能有一些反思。 I'm doing following thing for manually check previous versions during deserialization.
我正在做以下事情,以便在反序列化期间手动检查以前的版本。
First use IExtensibleDataObject for a Item class: 首先对Item类使用IExtensibleDataObject :
[DataContract(Namespace = "blah")]
public class Item : IExtensibleDataObject
{
[DataMember(Order = 0)]
public int Index { get; set; }
[DataMember(Order = 1)]
public ItemSourcesCollection Sources { get; set; }
}
Now the tricky thing for deserialized method: 现在反序列化方法很棘手:
/// <summary>
/// The deserialized.
/// </summary>
/// <param name="context">
/// The streaming context.
/// </param>
[OnDeserialized]
private void Deserialized(StreamingContext context)
{
// reflection for backward compatibilty only
if (this.ExtensionData == null)
{
return;
}
IList members = this.CheckForExtensionDataMembers();
if (members == null)
{
return;
}
string value = this.GetExtensionDataMemberValue(members, "ItemSource");
// do something with value
value = this.GetExtensionDataMemberValue(members, "ErrorSource");
// do something with value
}
/// <summary>
/// The check for extension data members.
/// </summary>
/// <returns>
/// Thel list of extension data memebers.
/// </returns>
private IList CheckForExtensionDataMembers()
{
PropertyInfo membersProperty = typeof(ExtensionDataObject).GetProperty(
"Members", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
var members = (IList)membersProperty.GetValue(this.ExtensionData, null);
if (members == null || members.Count <= 0)
{
return null;
}
return members;
}
/// <summary>
/// The get extension data member value.
/// </summary>
/// <param name="members">
/// The members.
/// </param>
/// <param name="dataMemberName">
/// The data member name.
/// </param>
/// <returns>
/// Returns extension data member value.
/// </returns>
private string GetExtensionDataMemberValue(IList members, string dataMemberName)
{
string innerValue = null;
object member =
members.Cast<object>().FirstOrDefault(
m =>
((string)m.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).GetValue(m, null)).Equals(
dataMemberName, StringComparison.InvariantCultureIgnoreCase));
if (member != null)
{
PropertyInfo valueProperty = member.GetType().GetProperty("Value", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
object value = valueProperty.GetValue(member, null);
PropertyInfo innerValueProperty = value.GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Public);
object tmp = innerValueProperty.GetValue(value, null);
var s = tmp as string;
if (s != null)
{
innerValue = s;
}
}
return innerValue;
}
All above stuff will be inside Item class. 以上所有内容都将在Item类中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.