序列化的概念
序列化是指一個對象的執行個體可以被儲存,儲存成一個二進位串,當然,一旦被儲存成二進位串,那麼也可以儲存成文本串了。
比如,一個計數器,數值為2,我們可以用字串“2”表示。
如果有個對象,叫做connter,當前值為2,那麼可以序列化成“2”,反向的,也可以從“2”得到值為2的計數器執行個體。
這樣,關機時序列化它,開機時還原序列化它,每次開機都是延續的。不會都是從頭開始。
序列化概念的提出和實現,可以使我們的應用程式的設定資訊儲存和讀取更加方便。
序列化有很多好處,比如,在一台機器上產生一個執行個體,初始化完畢,然後可以序列化,通過網路傳送到另一台機器,然後還原序列化,得到對象執行個體,之後再執行某些商務邏輯,得到結果,再序列化,返回第一台機器,第一台機器得到對象執行個體,得到結果。
這個例子是目前比較先進的“智能代理”的原理。
當前比較熱火的web services使用soap協議,soap協議也是以對象的可序列化為基礎的。
一 概述
.NET Framework為處理XML資料提供了許多不同的類庫。XmlDocument類能讓你像處理檔案一樣處理xml資料,而XmlReader、XmlWriter和它們的衍生類別使你能夠將xml資料作為資料流處理。
XmlSerializer則提供了另外的方法,它使你能夠將自己的對象序列化和反序列化為xml。序列化資料既能夠讓你像處理檔案一樣對資料進行隨機處理,同時又能跳過你不感興趣的資料。
二 主要類庫介紹
.NET 支援對象xml序列化和還原序列化的類庫主要位於命名空間System.Xml.Serialization中。
1. XmlSerializer 類
該類用一種高度鬆散耦合的方式提供序列化服務。你的類不需要繼承特別的基類,而且它們也不需要實現特別的介面。相反,你只需在你的類或者這些類的公用域以及讀/寫屬性裡加上自訂的特性。XmlSerializer通過反射機制讀取這些特性並用它們將你的類和類成員映射到xml元素和屬性。
2. XmlAttributeAttribute 類
指定類的公用域或讀/寫屬性對應xml檔案的Attribute。
例:[XmlAttribute(“type”)] or [XmlAttribute(AttributeName=”type”)]
3. XmlElementAttribute類
指定類的公用域或讀/寫屬性對應xml檔案的Element。
例:[XmlElement(“Maufacturer”)] or [XmlElement(ElementName=”Manufacturer”)]
4. XmlRootAttribute類
Xml序列化時,由該特性指定的元素將被序列化成xml的根項目。
例:[XmlRoot(“RootElement”)] or [XmlRoot(ElementName = “RootElements”)]
5. XmlTextAttribute 類
Xml序列化時,由該特性指定的元素值將被序列化成xml元素的值。一個類只允許擁有一個該屬性類別的執行個體,因為xml元素只能有一個值。
6. XmlIgnoreAttribute類
Xml序列化時不會序列化該特性指定的元素。
三 執行個體
下面例子中的xml schema 描述了一個簡單的人力資源資訊,其中包含了xml的大部分格式,如xml 元素相互嵌套, xml元素既有元素值,又有屬性值。
1. 待序列化的類階層
[XmlRoot("humanResource")]
public class HumanResource
{
#region private data.
private int m_record = 0;
private Worker[] m_workers = null;
#endregion
[XmlAttribute(AttributeName="record")]
public int Record
{
get { return m_record; }
set { m_record = value; }
}
[XmlElement(ElementName="worker")]
public Worker[] Workers
{
get { return m_workers; }
set { m_workers = value; }
}
}
public class Worker
{
#region private data.
private string m_number = null;
private InformationItem[] m_infoItems = null;
#endregion
[XmlAttribute("number")]
public string Number
{
get { return m_number; }
set { m_number = value; }
}
[XmlElement("infoItem")]
public InformationItem[] InfoItems
{
get { return m_infoItems; }
set { m_infoItems = value; }
}
}
public class InformationItem
{
#region private data.
private string m_name = null;
private string m_value = null;
#endregion
[XmlAttribute(AttributeName = "name")]
public string Name
{
get { return m_name; }
set { m_name = value; }
}
[XmlText]
public string Value
{
get { return m_value; }
set { m_value = value; }
}
}
2. 序列化產生的xml結構
<?xml version="1.0" ?>
- <humanResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" record="2">
- <worker number="001">
<infoItem name="name">Michale</infoItem>
<infoItem name="sex">male</infoItem>
<infoItem name="age">25</infoItem>
</worker>
- <worker number="002">
<infoItem name="name">Surce</infoItem>
<infoItem name="sex">male</infoItem>
<infoItem name="age">28</infoItem>
</worker>
</humanResource>
3. 利用XmlSerializer類進行序列化和還原序列化的實現(一般利用緩衝機制實現xml檔案只解析一次。)
public sealed class ConfigurationManager
{
private static HumanResource m_humanResource = null;
private ConfigurationManager(){}
public static HumanResource Get(string path)
{
if (m_humanResource == null)
{
FileStream fs = null;
try
{
XmlSerializer xs = new XmlSerializer(typeof(HumanResource));
fs = new FileStream(path, FileMode.Open, FileAccess.Read);
m_humanResource = (HumanResource)xs.Deserialize(fs);
fs.Close();
return m_humanResource;
}
catch
{
if (fs != null)
fs.Close();
throw new Exception("Xml deserialization failed!");
}
}
else
{
return m_humanResource;
}
}
public static void Set(string path, HumanResource humanResource)
{
if (humanResource == null)
throw new Exception("Parameter humanResource is null!");
FileStream fs = null;
try
{
XmlSerializer xs = new XmlSerializer(typeof(HumanResource));
fs = new FileStream(path, FileMode.Create, FileAccess.Write);
xs.Serialize(fs, humanResource);
m_humanResource = null;
fs.Close();
}
catch
{
if (fs != null)
fs.Close();
throw new Exception("Xml serialization failed!");
}
}
}
四 說明
1. 需要序列化為xml元素的屬性必須為讀/寫屬性;
2. 注意為類成員設定預設值,儘管這並不是必須的。
有關.NET中序列化的一些知識
“序列化”可被定義為將對象的狀態儲存到儲存媒介中的過程。在此過程中,對象的公用欄位和私人欄位以及類的名稱(包括包含該類的程式集)都被轉換為位元組流,然後寫入資料流。在以後“還原序列化”該對象時,建立原始對象的精確複本。
一、為什麼要選擇序列化
一個原因是將對象的狀態保持在儲存媒體中,以便可以在以後重新建立精確的副本;
另一個原因是通過值將對象從一個應用程式定義域發送到另一個應用程式定義域中。
例如,序列化可用於在 ASP.NET 中儲存工作階段狀態並將對象複製到 Windows 表單的剪貼簿中。遠端還可以使用序列化通過值將對象從一個應用程式定義域傳遞到另一個應用程式定義域中。
二、如何?對象的序列化及還原序列化
要實現對象的序列化,首先要保證該對象可以序列化。而且,序列化只是將對象的屬性進行有效儲存,對於對象的一些方法則無法實現序列化的。
實現一個類可序列化的最簡便的方法就是增加Serializable屬性標記類。如:
[Serializable()]
public class MEABlock
{
private int m_ID;
public string Caption;
public MEABlock()
{
///建構函式
}
}
即可實現該類的可序列化。
要將該類的執行個體序列化為到檔案中?.NET FrameWork提供了兩種方法:
1、XML序列化
使用 XmLSerializer 類,可將下列項序列化。
公用類的公用讀取/寫屬性和欄位
實現 ICollection 或 IEnumerable 的類。(注意只有集合會被序列化,而公用屬性卻不會。)
XmlElement 對象。
XmlNode 對象。
DataSet 對象。
要實現上述類的執行個體的序列化,可參照如下例子:
MEABlock myBlock = new MEABlock();
// Insert code to set properties and fields of the object.
XmlSerializer mySerializer = new XmlSerializer(typeof(MEABlock));
// To write to a file, create a StreamWriter object.
StreamWriter myWriter = new StreamWriter("myFileName.xml");
mySerializer.Serialize(myWriter, MEABlock);
需要注意的是XML序列化只會將public的欄位儲存,對於私人欄位不予於儲存。
產生的XML檔案格式如下:
<MEABlock>
<Caption>Test</Caption>
</MEABlock>
對於對象的還原序列化,則如下:
MEABlock myBlock;
// Constructs an instance of the XmlSerializer with the type
// of object that is being deserialized.
XmlSerializer mySerializer = new XmlSerializer(typeof(MEABlock));
// To read the file, creates a FileStream.
FileStream myFileStream = new FileStream("myFileName.xml", FileMode.Open);
// Calls the Deserialize method and casts to the object type.
myBlock = (MEABlock)mySerializer.Deserialize(myFileStream)
2、二進位序列化
與XML序列化不同的是,二進位序列化可以將類的執行個體中所有欄位(包括私人和公有)都進行序列化操作。這就更方便、更準確的還原了對象的副本。
要實現上述類的執行個體的序列化,可參照如下例子:
MEABlock myBlock = new MEABlock();
// Insert code to set properties and fields of the object.
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin",FileMode.Create,FileAccess.Write, FileShare.None);
formatter.Serialize(stream, myBlock);
stream.Close();
對於對象的還原序列化,則如下:
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Open,FileAccess.Read, FileShare.Read);
MEABlock myBlock = (MEABlock) formatter.Deserialize(stream);
stream.Close();
三、如何變相實現自訂可視化控制項的序列化、還原序列化
對於WinForm中自訂控制項,由於繼承於System.Windows.Form類,而Form類又是從MarshalByRefObject繼承的,表單本身無法做到序列化,表單的實現基於Win32下GUI資源,不能脫離當前上下文存在。
當然可以採用變通的方法實現控制項的序列化。這裡採用的是記憶類模型。
定義記憶類(其實就是一個可序列化的實體類)用於記錄控制項的有效屬性,需要序列化控制項的時候,只需要將該控制項的執行個體Copy到記憶類,演變成序列化儲存該記憶類的操作。
還原序列化是一個逆過程。將資料流還原序列化成為該記憶類,再根據該記憶類的屬性產生控制項執行個體。而對於控制項的一些事件、方法則可以繼續使用。
介紹 XML 序列化
.NET Framework 開發員指南
序列化是將對象轉換為容易傳輸的格式的過程。例如,可以序列化一個對象,然後使用 HTTP 通過 Internet 在用戶端和伺服器之間傳輸該對象。在另一端,還原序列化將從該流重新構造對象。
XML 序列化僅將對象的公用欄位和屬性值序列化為 XML 流。XML 序列化不包括類型資訊。例如,如果您有一個存在於 Library 命名空間中的 Book 對象,將不能保證它將會被還原序列化為同一類型的對象。
注意 XML 序列化不轉換方法、索引器、私人欄位或唯讀屬性(唯讀集合除外)。若要序列化對象的所有欄位和屬性(公用的和私人的),請使用 BinaryFormatter,而不要使用 XML 序列化。
XML 序列化中最主要的類是 XmlSerializer 類,它的最重要的方法是 Serialize 和 Deserialize 方法。XmlSerializer 產生的 XML 流符合全球資訊網協會 (http://www.w3.org/) XML 結構定義語言 (XSD) 1.0 的建議。另外,產生的資料類型符合標題為“XML Schema Part 2: Datatypes”(XML 結構描述第二部分:資料類型)的文檔。
對象中的資料是用程式設計語言構造(如類、欄位、屬性、基元類型、數組,甚至 XmlElement 或 XmlAttribute 對象形式的嵌入 XML)來描述的。您可以建立自己的用屬性批註的類,或者使用 XML 結構描述定義工具產生基於現有 XML 結構描述的類。
如果您有 XML 結構描述,就可運行 XML 結構描述定義工具產生一組強型別化為架構並用屬性批註的類。當序列化這樣的類的執行個體時,產生的 XML 符合 XML 結構描述。使用這樣的類,就可針對容易操作的物件模型進行編程,同時確保產生的 XML 符合 XML 結構描述。這是使用 .NET Framework 中的其他類(如 XmlReader 和 XmlWriter 類)分析和寫 XML 流的一種替換方法。(有關使用這些類的更多資訊,請參見使用 .NET Framework 中的 XML。)這些類使您可以分析任何 XML 流。與此相反,當需要 XML 流符合已知的 XML 結構描述時,請使用 XmlSerializer。
屬性控制由 XmlSerializer 類產生的 XML 流,使您可以設定 XML 流的 XML 命名空間、元素名、屬性名稱等。有關這些屬性和它們如何控制 XML 序列化的更多資訊,請參見使用屬性控制 XML 序列化。若想獲得一個列示對所產生的 XML 起控製作用的那些屬性的表,請參見控制 XML 序列化的屬性。
XmlSerializer 類可進一步序列化對象並產生編碼的 SOAP XML 流。產生的 XML 符合標題為“Simple Object Access Protocol (SOAP) 1.1”的全球資訊網協會文檔的第 5 節。有關此過程的更多資訊,請參見用 XML 序列化產生 SOAP 訊息。有關控制產生的 XML 的屬性工作表,請參見控制編碼的 SOAP 序列化的屬性。
XmlSerializer 類產生由 XML Web services 建立和傳遞給 XML Web services 的 SOAP 訊息。若要控制 SOAP 訊息,可將屬性應用於 XML Web services 檔案 (.asmx) 中的類、傳回值、參數和欄位。您可以同時使用在“控制 XML 序列化的屬性”中列出的屬性和在“控制編碼的 SOAP 序列化的屬性”中列出的屬性,因為 XML Web services 可以使用文本樣式,也可以使用編碼的 SOAP 樣式。有關使用屬性控制 XML Web services 所產生的 XML 的更多資訊,請參見 XML Web services 的 XML 序列化。有關 SOAP 和 XML Web services 的更多資訊,請參見自訂 SOAP 訊息。
保護 XmlSerializer 應用程式
在建立使用 XmlSerializer 的應用程式時,您應當瞭解以下幾點以及它們的影響:
XmlSerializer 建立 C# 檔案 (.cs 檔案),並將其編譯成 .DLL 檔案,這些 .DLL 檔案位於由 TEMP 環境變數指定的目錄中;這些 DLL 檔案將發生序列化。
代碼和 DLL 在建立和進行編譯時間,易於遭受惡意進程的攻擊。如果所使用的電腦啟動並執行是 Microsoft Windows NT 4.0 或更高版本,則有可能會有兩個或更多使用者共用臨時目錄。如果同時存在以下兩種情況,則共用臨時目錄是有危險性的:(1) 兩個帳戶有不同的安全特權;(2) 具有較高特權的帳戶運行一個使用 XmlSerializer 的應用程式。在這種情況下,某一使用者可以替換所編譯的 .cs 或 .DLL 檔案,由此破壞電腦的安全性。為了避免發生這一問題,請始終確保電腦上的每一帳戶都有自己的設定檔。如果能夠保證這一點的話,預設情況下,TEMP 環境變數就會為不同的帳戶指定不同的目錄。
如果一名惡意使用者向 Web 服務器發送持續的 XML 資料流(拒絕服務的攻擊),XmlSerializer 會一直處理這一資料,直到電腦資源不夠用才停止。
如果您所使用的電腦運行 Internet 資訊服務 (IIS),並且您的應用程式是在 IIS 下運行,就可以避免這類攻擊。IIS 帶有一個控制門,用于禁止處理大於設定數量(預設值是 4 KB)的資料流。如果您所建立的應用程式不使用 IIS,同時該應用程式使用 XmlSerializer 進行還原序列化,則應該實現一個類似的控制門,以阻止拒絕服務的攻擊。
XmlSerializer 將使用給予它的任何類型,對資料進行序列化,並運行任何代碼。
惡意對象施加威脅的方式有兩種。一種是運行惡意代碼,另一種是將惡意代碼插入到由 XmlSerializer 建立的 C# 檔案中。在第一種情況下,如果惡意對象試圖運行破壞性過程,程式碼存取安全性將協助防止發生任何破壞。在第二種情況下,在理論上,惡意對象有可能會以某種方式將代碼插入到由 XmlSerializer 建立的 C# 檔案中。儘管對這一問題已進行了徹底的檢驗,而且這類攻擊被認為是不可能的,但您還是應該小心一些,一定不要序列化那些不可信的未知類型的資料。
已序列化的重要資料可能易於遭到攻擊。
XmlSerializer 對資料進行了序列化之後,資料可以被儲存為 XML 檔案,或儲存在其他資料存放區區。如果其他進程可以訪問到您的資料存放區區,或是可以在 Intranet 或 Internet 上看到該資料存放區區,資料就可能被竊取,並被惡意使用。例如,如果您建立了一個應用程式,對包含信用卡號碼的訂單進行序列化,這一資料就非常重要。為了防止發生這一問題,請始終保護您的資料存放區區,並對資料採取保密措施。
簡單類的序列化
下面的樣本顯示一個具有公用欄位的簡單類:
[Visual Basic]Public Class OrderForm Public OrderDate As DateTimeEnd Class[C#]public class OrderForm{ public DateTime OrderDate;}當將此類的執行個體序列化時,該執行個體可能類似於下面的代碼:
<OrderForm> <OrderDate>12/12/01</OrderDate></OrderForm>有關序列化的更多樣本,請參見 XML 序列化的樣本。
可以序列化的項
使用 XmLSerializer 類,可將下列項序列化。
公用類的公用讀取/寫屬性和欄位
實現 ICollection 或 IEnumerable 的類。(注意只有集合會被序列化,而公用屬性卻不會。)
XmlElement 對象。
XmlNode 對象。
DataSet 對象。
序列化和還原序列化對象
若要序列化對象,首先建立要序列化的對象並設定它的公用屬性和欄位。為此,必須確定要用以儲存 XML 流的傳輸格式(或者作為流,或者作為檔案)。例如,如果 XML 流必須以永久形式儲存,則建立 FileStream 對象。當您還原序列化對象時,傳輸格式確定您將建立流還是檔案對象。確定了傳輸格式之後,就可以根據需要調用 Serialize 或 Deserialize 方法。
序列化對象
建立對象並設定它的公用欄位和屬性。
使用該對象的類型構造 XmlSerializer。有關更多資訊,請參見 XmlSerializer 類建構函式。
調用 Serialize 方法以產生對象的公用屬性和欄位的 XML 流表示形式或檔案表示形式。下面的樣本建立一個檔案。
[Visual Basic]Dim myObject As MySerializableClass = New MySerializableClass()' Insert code to set properties and fields of the object.Dim mySerializer As XmlSerializer = New XmlSerializer(GetType(MySerializableClass))' To write to a file, create a StreamWriter object.Dim myWriter As StreamWriter = New StreamWriter("myFileName.xml")mySerializer.Serialize(myWriter, myObject)[C#]MySerializableClass myObject = new MySerializableClass();// Insert code to set properties and fields of the object.XmlSerializer mySerializer = new XmlSerializer(typeof(MySerializableClass));// To write to a file, create a StreamWriter object.StreamWriter myWriter = new StreamWriter("myFileName.xml");mySerializer.Serialize(myWriter, myObject);還原序列化對象
使用要還原序列化的對象的類型構造 XmlSerializer。
調用 Deserialize 方法以產生該對象的副本。在還原序列化時,必須將返回的對象強制轉換為原始對象的類型,如下面的樣本中所示。下面的樣本將該對象還原序列化為檔案,儘管它也可以被還原序列化為流。
[Visual Basic]Dim myObject As MySerializableClass' Constructs an instance of the XmlSerializer with the type' of object that is being deserialized.Dim mySerializer As XmlSerializer = New XmlSerializer(GetType(MySerializableClass))' To read the file, creates a FileStream.Dim myFileStream As FileStream = _New FileStream("myFileName.xml", FileMode.Open)' Calls the Deserialize method and casts to the object type.myObject = CType( _mySerializer.Deserialize(myFileStream), MySerializableClass)[C#]MySerializableClass myObject;// Constructs an instance of the XmlSerializer with the type// of object that is being deserialized.XmlSerializer mySerializer = new XmlSerializer(typeof(MySerializableClass));// To read the file, creates a FileStream.FileStream myFileStream = new FileStream("myFileName.xml", FileMode.Open);// Calls the Deserialize method and casts to the object type.myObject = (MySerializableClass) mySerializer.Deserialize(myFileStream)有關 XML 序列化的更多樣本,請參見 XML 序列化的樣本。
使用 XML 序列化的好處
XmlSerializer 類在您將對象序列化為 XML 時為您提供完整而靈活的控制。如果您正在建立 XML Web services,則可以將控制序列化的屬性應用於類和成員以確保 XML 輸出符合特定的架構。
例如,XmlSerializer 使您能夠:
指定應將欄位或屬性編碼為特性還是元素。
指定要使用的 XML 命名空間。
如果欄位或屬性名稱不合適,則指定元素或特性的名稱。
XML 序列化的另一個好處是:只要產生的 XML 流符合給定的架構,則對於所開發的應用程式就沒有約束。假定有這樣一個用於描述圖書的架構,它具有標題、作者、出版商和 ISBN 編號元素。您可以開發一個以您希望的任何方式(例如,作為圖書訂單,或作為圖書清單)處理 XML 資料的應用程式。在任一種情況下,唯一的要求是 XML 流應當符合指定的 XML 結構定義語言 (XSD) 架構。
XML 序列化注意事項
使用 XmlSerializer 類時,應考慮下列情況:
序列化資料只包含資料本身以及類的結構。不包括類型標識和程式集資訊。
只能序列化公用屬性和欄位。如果需要序列化非公用資料,請使用 BinaryFormatter 類而不是 XML 序列化。
類必須有一個將由 XmlSerializer 序列化的預設建構函式。
不能序列化方法。
XmlSerializer 可以以不同方式處理實現 IEnumerable 或 ICollection 的類(條件是這些類滿足某些要求)。實現 IEnumerable 的類必須實現帶單個參數的公用 Add 方法。Add 方法的參數必須與從 GetEnumerator 方法返回的 IEnumerator.Current 屬性所返回的類型一致(多態)。除實現 IEnumerable 外還實現 ICollection 的類(如 CollectionBase)必須有一個取整數的公用 Item 索引屬性(在 C# 中為索引器),並且它必須有一個整數類型的公用 Count 屬性。傳遞給 Add 方法的參數必須與從 Item 屬性返回的類型相同或與該類型的某個基的類型相同。對於實現 ICollection 的類,要序列化的值將從索引 Item 屬性檢索,而不是通過調用 GetEnumerator 來檢索。另外請注意,除返回另一個集合類(實現 ICollection 的集合類)的公用欄位之外,將不序列化公用欄位和屬性。有關樣本,請參見 XML 序列化的樣本。
XSD 資料類型映射
標題為“XML Schema Part 2: Datatypes”的全球資訊網協會 (http://www.w3.org/) 文檔指定在 XML 結構定義語言 (XSD) 架構中允許使用的單一資料型別。對於這些資料類型中的許多類型(例如,int 和 decimal),在 .NET Framework 中都有對應的資料類型。但是,某些 XML 資料類型在 .NET Framework 中沒有對應的資料類型(例如,NMTOKEN 資料類型)。在這樣的情況下,如果使用 XML 結構描述定義工具 (Xsd.exe) 從架構產生類,就會將適當的特性應用於字串類型的成員,並會將其 DataType 屬性設定為 XML 資料類型名稱。例如,如果架構包含一個資料類型為 XML 資料類型 NMTOKEN 的、名為“MyToken”的元素,則產生的類可能包含以下樣本中的成員。
[Visual Basic]<XmlElement(DataType:="NMTOKEN")>Public MyToken As String[C#][XmlElement(DataType = "NMTOKEN")]public string MyToken;與此類似,如果建立一個必須符合特定 XML 結構描述 (XSD) 的類,應當應用適當的特性並將它的 DataType 屬性設定為所需的 XML 資料類型名稱。
有關類型映射的完整列表,請參見下列任意一個屬性類別的 DataType 屬性:SoapAttributeAttribute、SoapElementAttribute、XmlArrayItemAttribute、XmlAttributeAttribute、XmlElementAttribute 或 XmlRootAttribute。
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/shizhiyingnj/archive/2007/02/11/1507943.aspx