序列化是將一個對象保存到存儲介質上或者將對象進行轉換使之能夠在網絡上傳送的行為。在一個對象被序列化之後,你會想要將它反序列化,也就是將數據重新轉換為可用的對象的行為。這種類型的功能被用在一個對象必須被從一個上下文封送到另一個上下文的時候,例如當對象跨越App域的時候。另外一個例子是Web服務——對象在服務器上被序列化,通過網絡被(封送或)發送到的客戶端,然後被反序列化成有用的對象。
從二進制到XML,.NET框架為開發人員提供了很多序列化選項,甚至允許開發人員創建自己的序列化例程。在本文中,我將著重討論XML的序列化,並告訴你如何利用這一內置的功能。
XML序列化
.NET框架提供的一種形式的序列化是XML序列化。在這種類型的序列化裡,對象狀態被以XML格式保存。這使得被序列化的對象能夠被不同的系統取得並修改,甚至是那些不是用.NET編寫的系統。另外一個優勢是被序列化的對象對於人來說是可讀和可寫的——因此更新對象的方式莫過於打開寫字板更改其值。
XML序列化常常被來遠程控制項目和Web服務項目裡,雖然你可能會在別的地方發現它,比如DataSet封送。在與Xpath查詢和Predicate方法一起使用的時候,XML序列化能夠被用來實現面向對象的數據庫——我會在今後的文章裡談這方面的內容。
使用XML序列化
在.NET框架裡利用內置的XML序列化方法相對較為容易。你只需要熟悉一些類和屬性就可以開始使用簡單的XML序列化了:
System.Xml.Serialization命名空間:含有使用XML序列化所需要的類和功能。這個命名空間應該被放在使用XML序列化的類的頂部的一個“using”命令裡。
XmlSerializer類:提供將對象序列化和反序列化的功能。
XmlIgnore屬性:告訴XmlSerializer類跳過你不希望序列化的成員。
這個列表只不過讓你對序列化有一個初步的了解。還有更多的對象可以供你在使用XML序列化的時候使用。
下面代碼是將Customer對象序列化的一個簡單例子。這個Customer對象在下載文件的示例應用程序裡被定義。
Customer customer = newCustomer(); customer.FirstName = "Zach"; customer.LastName = "Smith"; XmlSerializer serializer = newXmlSerializer(typeof(Customer)); StringWriter writer = newStringWriter(); serializer.Serialize(writer, customer); Console.WriteLine(writer.ToString());
正如你看到的,XML序列化是一個很簡單的過程。我們只需要創建一個需要被序列化的對象,創建用於這種類型對象的XmlSerializer,並調用XmlSerializer.Serialize。被序列化的對象然後被寫到提供的Stream裡——在本文中是一個叫做“writer”的StringWriter。
如果你看看被序列化的對象,你會注意到它很容易讀懂。下面就是被序列化的Customer對象的內容:
<?xml version="1.0" encoding="utf-16"?> <Customer xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Orders /> <LastName>Smith</LastName> <FirstName>Zach</FirstName> </Customer>
在這裡,你會看到Customer對象的屬性被序列化,也就是Order對象的列表。如果你將這個輸出與Customer類的定義比較一下,你會注意到“Income”屬性沒有被列出來。這是因為Income屬性本身還帶有一個XmlIgnore屬性,它會讓XML序列化庫在序列化的時候跳過Income屬性。在序列化過程中跳過屬性的一個副作用是這個屬性不會被反序列化,所以會在反序列化的時候總是帶有默認的值。
Orders節點是空的,因為這個客戶沒有下訂單。但是如果我們將含有訂單的Customer對象序列化,那麼我們就會得到類似下面的輸出:
<?xml version="1.0" encoding="utf-16"?> <Customer xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Orders> <Order> <Total>34.56</Total> </Order> <Order> <Total>156.56</Total> </Order> </Orders> <LastName>Smith</LastName> <FirstName>Zach</FirstName> </Customer>
要注意每個訂單對象都被單獨序列化並放在被序列化的Customer對象的Orders節點裡。如果你想要反序列化這個Customer對象,那麼相關聯的Order對象也會被反序列化。
注:要被序列化或者反序列化的每個對象都必須有一個空的默認構造函數。如果對象不實現一個空的構造函數,那麼就會引發異常。
反序列化對象
將對象反序列化就和將它們序列化一樣簡單。下面的代碼顯示了如何將反序列化保存在文件裡的對象:
XmlSerializer serializer = new XmlSerializer(typeof(Customer)); FileStream file = File.OpenRead(fileToWrite); Customer customer = (Customer)serializer.Deserialize(file); file.Close();
上面這段代碼與前面的序列化代碼的唯一不同之處在於我們在這裡調用了XmlSerializer.Deserialize。這個方法會返回一個對象,我們然後就必須轉到將要使用的對象類型上。
其他用法
在某些情況下,通過實現XML序列化來保存和檢索設置文件是很有用的。例如,你可以只用創建一個含有所需屬性的類並將它序列化到磁盤上,而不需要編寫一個自定義的XML分析例程來尋找和分析設置文件。這還允許你在需要的時候對文件進行手動編輯,讓你不需要自己編寫任何XML分析代碼。這種方式可以用於任何類型的信息,應用程序可能需要保存從一個執行到另一個執行的這種類型的信息。
正如我先前所說的,將XML序列化與Predicate方法(被編譯的搜索)、Xpath(特別搜索),以及XmlDocument(提供器)對象一起使用,你可以創建一個面向對象的數據庫,這是完全可行的。我已經在進行這樣一個項目,所以我會在以後的文章裡探討它背後所隱藏的實現和思想。其目標是利用不超過200行的C#代碼就創建完全可實現的面向對象的數據庫。
發揮XML序列化的優勢
既然你已經熟悉XML序列化了,那麼我希望你能夠在自己的項目裡找到它的用武之地。從我個人來講,我通過對復雜的應用程序設置使用XML序列化節省了大量的時間,這還不算上我應用程序的其他一些模塊。所以我希望本文能夠不讓你犯我曾經犯過的錯誤!