c# - DataContract 向后兼容序列化

标签 c# .net serialization backwards-compatibility datacontract

我上过这样的课:

[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; }
}

我有很多它的序列化副本(在文件中)(包括一些生产文件), 现在我的任务是将此类更改为以下内容:

[DataContract(Namespace = "blah")]
public class Item
{
    [DataMember(Order = 0)]
    public int Index { get; set; }

    [DataMember(Order = 1)]
    public ItemSourcesCollection Sources { get; set; }
}

ItemSourcesCollection 在哪里

[CollectionDataContract(ItemName = "ItemSourceItem", Namespace = "blah")]
public class ItemSourcesCollection : List<ItemSource> {}

ItemSource 在哪里

[DataContract]
public class ItemSource
{
    [DataMember]
    public Uri SourcePath { get; set; }

    [DataMember]
    public ItemSourceType Type { get; set; }
}

ItemSourceType 在哪里

[Serializable]
public enum ItemSourceType 
{
    Data,

    Errors
}

问题是向后兼容性。旧的序列化项目是否有可能被正确反序列化?迁移具有向后兼容性的数据协定的最佳实践/模式是什么?

最佳答案

是的,经过一些思考是可能的。我正在做以下事情以在反序列化期间手动检查以前的版本。

第一次使用IExtensibleDataObject对于 Item 类:

[DataContract(Namespace = "blah")]
public class Item : IExtensibleDataObject
{
    [DataMember(Order = 0)]
    public int Index { get; set; }

    [DataMember(Order = 1)]
    public ItemSourcesCollection Sources { get; set; }
}

现在是反序列化方法的棘手问题:

    /// <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;
    }

以上所有内容都将在 Item 类中。

关于c# - DataContract 向后兼容序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9992469/

相关文章:

c# - 如何指定要返回的 SQL 层次结构级别?

c# - 获取 IIS 应用程序文件系统路径

java - 在 Java 对象之间复制数据的最快方法是什么?

c# - 接收 HTTP 响应错误时发生错误

c# - javascript 和 c# 中的传递参数问题

c# - 被调用实例方法中的锁定问题

c# - 如何在 .net 中将 SID 转换为字符串

c# - 检测 WPF 中的系统主题更改

swift - 了解 Alamofire 的响应对象序列化闭包的使用

c# - 覆盖 XML 反序列化以使用基本反序列化并添加功能