2010-08-10 53 views
2

其實我有這樣重命名標有一個DataMemberAttribute

[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序列化的文件應該站出來與FullName,而它仍然有可能在舊文件閱讀。

要獲得新的屬性名出到一個新的文件是很容易的。只需重命名屬性,你就完成了。

爲了兼容性,我會用[DataMember(Name="Name")]來標記新的屬性名稱,但在這種情況下,如果我把這個類寫回到一個文件中,我得到了寫入的舊名稱。

所以存在有什麼東西在DataContract,我可以記住我的財產FullName

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

也許兩次或有任何其他機制如何,我可以表明,這兩個值可以被寫入這一點,但只有一個寫回來會出來嗎?

我能想象得到的唯一方法是創建一個類LegacyItem,它沒有功能或類似的東西,但滿足舊的DataContract。另外還有一些隱式/顯式運算符,用於將我的LegacyItem轉換爲Item。最後但並非最不重要的反序列化,我必須做一些測試(也許只是一個簡單的try/catch)找出類我應該告訴DataContractSerializer的讀取文件。

所以,即使這種做法將有可能聽起來這個任務有點過於複雜,我想知道,如果沒有框架內已有的東西,這將使這個任務稍微容易一些。

回答

3

如果你不介意在你的班上一點點過時的代碼(這無論如何會比你建議的整個第二類代碼更少),那麼你可以這樣做:

[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訪問器序列化爲FullName。在序列化時,舊屬性總是返回null,而不是事件發送到序列化的XML。

也是如此,這是不是類的外部可見你可以標記過時的財產作爲私有。

一對夫婦的提示前進的,我寧願不使用自動屬性DataMember性能。事實上,我通常將背景字段標記爲DataMember。最好始終包含DataMember屬性的可選Name參數。我承認我並不總是這樣做,但這是一個好習慣,因爲如果您重構 - >在Visual Studio中重命名屬性或字段,那麼您不會意外地違反合同。

UPDATE

的OP奧利弗提出了另一個解決自己...這裏是什麼樣子對於那些有興趣。

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

首先感謝回答這個老問題。我也已經用數據成員屬性和名稱參數裝飾了後備字段。目前我也使用某種過時的字段,但不要使用它的setter來重定向。相反,我添加了一個'OnDeserialized'方法來執行* translation *到新結構中。所以我可以更好地控制字段的設置順序,或者更容易調用一些內部幫助器方法。 – Oliver 2014-01-29 07:09:11

0

你應該看看IExtensibleDataObject界面和相應ExtensionDataObject領域。它將需要一些自定義代碼才能正常工作,但將有助於解決您的問題。

+0

正如你所看到的,我已經使用'ExtensionDataObject'來允許往返。但是我找不到有關如何訪問其中的數據的任何信息。如果你看看[MSDN](http://msdn.microsoft.com/en-us/library/system.runtime.serialization.extensiondataobject.aspx),你會發現沒有任何東西可以用來獲取數據它(或者我錯過了什麼?) – Oliver 2011-06-06 12:41:24