2010-02-26 46 views
5

是否可以使用任何標準序列化器反序列化對象屬性,而無需創建新對象?將屬性反序列化到預先存在的對象中

問題是,所討論的對象非常複雜(它們只能由特殊的工廠創建,並且它們的類型是在運行時動態生成的),但它們有一些已知的屬性,我希望在外部存儲文件(最好是xml,但二進制文件也可以),以後(可能在重新啓動應用程序後),我想要將存儲的屬性設置回我提供的對象。

似乎所有的標準序列化器都只能爲我生成一個新的對象(這也需要一個公共無參數的構造器),從中我將不得不手動分配所有的屬性。這與我想避免的手動序列化沒有多大區別,因爲一組序列化屬性非常大,在項目生命週期中可能會改變幾次。在這一點上,我很接近編寫自己的輕量級序列化器,但也許有人可以提出一個更標準的方法來做這樣的事情?

回答

3

protobuf-net有一個Serializer.Merge方法可讓您反序列化到現有實例。只有在流中找到的值被寫入(它不會擦除對象)。

不是微軟,但相當穩定。

爲了擴大這個;獲得強大的序列化處理所有常見的場景是(我從痛苦的經驗中知道)很多工作。我的建議絕對是在可能的情況下重新使用現有的代碼。 protobuf網似乎提供你需要的一切;目前的二進制文件只需要你裝飾你的班級(與WCF的[DataContract]非常相似 - 實際上它甚至支持[DataContract]/[DataMember]),但工作到位可以使其即使對付POCO也是如此 - 所以你可以在外部使用它你的控制。

+0

這不是在字段級別而是在請求的屬性級別上工作嗎? – Lucero 2010-02-26 12:43:57

+0

@Lucero - 它可以在字段和屬性上工作;這取決於你告訴它做什麼。 – 2010-02-26 12:48:26

+0

非常感謝您提供了一個有趣的鏈接,但我不想讓這樣一個相當簡單的任務涉及全新的第三方組件。另外缺點是它不是xml。 – Chriso 2010-02-26 13:02:18

0

你可以實現你自己靈活的「序列化器」來處理這個問題。反射爲您提供所需的一切。

0

你可以使用FormatterServices.PopulateObjectMembers方法,這似乎正好是專爲這個任務......

+1

到那時,你將不得不解析流來獲取值到'object's,*和*獲得'MemberInfo's,*和*處理所有複雜的子數據等。說實話,只要有一個方法來設置這些值就可以提供很少的內容 - 在這一點上,你可以使用反射。 – 2010-02-26 12:51:58

2

可以使用FormatterServices類。

你有一類書:

[Serializable] 
class Book 
{ 
    public string Title { get; set; } 

    public string Author { get; set; } 

    // Constructor for setting new values. 
    public Book(string title, string author) 
    { 
     Title = title; 
     Author = author; 
    } 
} 

可以序列它是這樣的:

var book = new Book("Moby Dick", "Herman Melville"); 

string path = Path.GetTempFileName(); 

var bf = new BinaryFormatter(); 
using (var fs = new FileStream(path, FileMode.Create)) 
    bf.Serialize(fs, book); 

如果你的對象被修改:

// Edit object 
book.Title = "Foo"; 
Console.WriteLine("{0}, {1}", book.Title, book.Author); 

你可以用它恢復以下代碼:

Book temp; 
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
    temp = (Book) bf.Deserialize(fs); 

MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof (Book)); 
FormatterServices.PopulateObjectMembers(book, members, FormatterServices.GetObjectData(temp, members)); 

// Object state is back 
Console.WriteLine("{0}, {1}", book.Title, book.Author); 
相關問題