代码之家  ›  专栏  ›  技术社区  ›  Oliver

重命名用DataMemberAttribute标记的类属性

  •  2
  • Oliver  · 技术社区  · 14 年前

    实际上我有一个这样的班

    [DataContract]
    public class Item : IExtensibleDataObject
    {
        [Browsable(false)]
        public virtual ExtensionDataObject ExtensionData { get; set; }
    
        [DataMember]
        public string ID { get; set; }
    
        [DataMember]
        public string Name { get; set; }
    
        public Item()
            : this(String.Empty, String.Empty)
        { }
    
        public Item(string id, string name)
        {
            ID = id ?? String.Empty;
            Name = name ?? String.Empty;
        }
    }
    

    您可以轻松地序列化和反序列化它。但现在最困难的是:

    我得改名 Name FullName 每个新的XML序列化文件都应该 全名 但仍然可以读取旧文件。

    将新的属性名导出到新文件中非常容易。只需重命名属性,即可完成操作。

    为了兼容性,我将用标记新属性名 [DataMember(Name="Name")] 但在这种情况下,如果我把这个类写回到一个文件中,就会得到一个旧的名字。

    所以存在于 DataContract 在那里我可以标记我的财产 全名 也许是两次

    [DataMember(Name="Name")]
    [DataMember]
    public string FullName { get; set}
    

    或者有没有其他的机制可以证明这两个值都可以写入,但只有一个值会在写回时出现?

    我能想象的唯一方法是创建一个类 LegacyItem 它没有任何功能或类似的东西,但满足旧的 数据通路 . 另外还有一种隐式/显式运算符来转换 法律条款 变成一个 Item . 最后但不是最不重要的是反序列化,我必须进行一些测试(可能只是一个简单的 try/catch )想知道我该告诉哪个班 DataContractSerializer 读取文件。

    因此,即使这种方法是可能的,对于这项任务来说,听起来也有点过于复杂了,我想知道,框架中是否已经没有什么东西可以使这项任务变得简单一点。

    2 回复  |  直到 10 年前
        1
  •  3
  •   TCC    10 年前

    如果你不介意在你的类中有一些过时的代码(无论如何,这比你建议的整个第二类的代码要少),那么你可以这样做:

    [DataContract]
    public class Item : IExtensibleDataObject
    {
        public virtual ExtensionDataObject ExtensionData { get; set; }
    
        [DataMember]
        public string ID { get; set; }
    
        [DataMember(Name = "Name", EmitDefaultValue = false)]
        private string _obsoleteName { get { return null; } set { if(value != null) FullName = value; } }
    
        [DataMember]
        public string FullName {get; set;}
    
        public Item()
            : this(String.Empty, String.Empty)
        { }
    
        public Item(string id, string name)
        {
            ID = id ?? String.Empty;
            FullName = name ?? String.Empty;
        }
    }
    

    可以读取旧的XML,反序列化时将正确分配给新属性。然后在序列化时,只有新属性将通过set访问器序列化为全名。序列化时,旧属性始终返回空值,而不是向序列化XML发出的事件。

    此外,还可以将过时属性标记为私有属性,以便在类外部不可见。

    接下来有几个提示,我不喜欢使用自动属性 DataMember 性质。事实上,我通常将支持字段标记为 数据仓库 . 最好总是包括可选的 Name 的参数 数据仓库 属性。我承认,我自己并不总是这样做,但这是一个很好的实践,因为这样一来,如果重构--重命名Visual Studio中的属性或字段,就不会意外地破坏合同。

    更新

    奥立弗亲手提出了另一个解决办法…这是那些感兴趣的人的样子。

    [DataContract]
    public class Item : IExtensibleDataObject
    {
        public virtual ExtensionDataObject ExtensionData { get; set; }
    
        [DataMember]
        public string ID { get; set; }
    
        [DataMember(Name = "Name", EmitDefaultValue = false)]
        private string _obsoleteName;
    
        [DataMember]
        public string FullName {get; set;}
    
        public Item()
            : this(String.Empty, String.Empty)
        { }
    
        public Item(string id, string name)
        {
            ID = id ?? String.Empty;
            FullName = name ?? String.Empty;
        }
    
        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            if(_obsoleteName != null && FullName == null)
            {
                //upgrade old serialized object to new version
                //by copying serialized Name field to newer FullName
                FullName = _obsoleteName;
    
                //set _obsoleteName to null so that it stops serializing
                _obsoleteName = null;
            }
        }
    }
    
        2
  •  0
  •   Matt Thomas    13 年前

    你应该看看 IExtensibleDataObject 接口和相应的 ExtensionDataObject 字段。它需要一些自定义代码才能使其正常工作,但这将有助于解决您的问题。