C#對象序列化(2)作者: 日期:2009-3-14 23:42:29 出處:淘特網
解析
對象序列化可以使對象的資料持久地儲存,對象狀態可以是Ssytem.IO.Stream的衍生類別型。並不是任何類型的對象都可以被序列化的,只有當其類型定義為可序列化時,該對象才可以被序列化。例如,自訂一個類類型,當該類類型被標記了[Serializable]特性後,其對象即可被序列化。序列化的代碼本身很簡單,並可使用多種格式儲存對象(或對象圖),如二進位格式、SOAP格式和XML格式。
將對象以二進位格式序列化,需要使用BinaryFormatter類型,該類型位於mscorlib.dll程式集,使用時只需匯入其命名空間即可,程式碼如以下代碼所示:
//匯入BinaryFormatter類的命名空間 using System.Runtime.Serialization.Formatters.Binary; //建立BinaryFormatter類對象MyBF BinaryFormatter MyBF = new BinaryFormatter(); //建立自訂類MyClass的對象引用obj,該類已經標記了[Serializable]特性 MyClass obj = new MyClass(); //建立Stream類型引用fs Stream fs = new FileStream(需要儲存的路徑, FileMode.Create, FileAccess.Write, FileShare.None); //調用MyBF的Serialize方法,傳遞fs和obj參數 MyBF.Serialize(fs, Pn); //關閉fs對象 fs.Close(); |
可見,只需調用BinaryFormatter類對象的Serialize()方法,即可完成序列化的操作。如果使用SOAP格式序列化,其操作和二進位格式基本一致,只是由SoapFormatter類的對象調用Serialize()方法。由於定義SoapFormatter類的命名空間是 System.Runtime. Serialization.Formatters.Soap,而這個命名空間定義於System.Runtime.Serialization. Formatters.Soap.dll程式集內,所以使用SoapFormatter類時,需手動引用該程式集,然後匯入該命名空間。實際上,BinaryFormatter類和SoapFormatter類都實現了IFormatter介面,所以在程式應用中,可以編寫相應的多態程式。
XML格式序列化對象需要建立System.Xml.Serialization.XmlSerializer類對象,然後調用 Serialize()方法。該類的命名空間雖然定義於System.Xml.dll程式集內,但是Visual Studio 2005/ Visual Studio 2008將自動引用該程式集,所以不需要手動引用System.Xml.dll程式集。XML格式序列化的方法如以下代碼所示:
//匯入XmlSerializer類的命名空間 using System.Xml.Serialization; //建立XmlSerializer類對象MyXS XmlSerializer MyXS = new XmlSerializer(typeof(MyClass), 要序列化其他對象的Type類型數組); //建立自訂類MyClass的對象引用obj,該類已經標記了[Serializable]特性 MyClass obj = new MyClass(); //建立Stream類型引用fs Stream fs = new FileStream(需要儲存的路徑, FileMode.Create, FileAccess.Write, FileShare.None); //調用MyXS的Serialize方法,傳遞fs和obj參數 MyXS.Serialize(fs, Pn); //關閉fs對象 fs.Close(); |
XmlSerializer類的建構函式需要傳遞參數,當只需要實現一個獨立對象時,傳遞該對象所屬類的Type物件類型即可,當該對象依賴於其他對象時,需要將其他對象所屬類的Type物件類型作為數組傳遞。
說明:對象圖是指一組關聯的對象關係圖,描述了多個對象之間的依賴關係。
面試例題21:如何將XML格式持久化的對象還原序列化?
考點:還原序列化的基本方法,處理還原序列化後的對象資料。
出現頻率:★★
解答
在Visual Studio 2005/ Visual Studio 2008中建立一個C#的Windows表單應用程式項目,並將其項目命名為ListSerialize。程式序列化的對象是List<T> 類的對象(該類是可序列化的),通過"添加"按鈕控制項,增加List<T>類對象中的子項,直到單擊"輸出XML"按鈕。而單擊"XML還原序列化"按鈕後,指定XML檔案中的對象資訊還原,並在ListBox控制項(命名為"XmlList")中輸出該對象的每個子項資料。在Visual Studio 2005/ Visual Studio 2008的"Form1.cs[設計]"視圖中建立基本的表單布局和控制項,控制項的命名7.50所示。
| |
| (點擊查看大圖)圖7.50 還原序列化程表單控制項布局及命名 |
編寫ListSerialize項目的Form1.cs如代碼7.26所示。
代碼7.26 還原序列化對象:Form1.cs
using System; ……………………………………… //匯入必要的命名空間 using System.Xml.Serialization; using System.Runtime.Serialization; using System.IO; namespace ListSerialize { public partial class Form1 : Form { //建立List<T>類型對象list,子項類型為PersonDetail List<PersonDetail> list = new List<PersonDetail>(); //聲明List<T>類型readlist變數,子項類型為PersonDetail List<PersonDetail> readlist; //聲明fn變數,用於隱藏檔路徑 string fn; public Form1() { InitializeComponent(); } private void AddBtn_Click(object sender, EventArgs e) { //建立PersonDetail類型對象Pd PersonDetail Pd = new PersonDetail(); //將兩個文字框控制項內容賦值給Pd的兩個對象 Pd.Name = nametxt.Text; Pd.Password = passwordtxt.Text; //list對象添加子項Pd list.Add(Pd); MessageBox.Show("添加成功"); } private void OutputBtn_Click(object sender, EventArgs e) { //擷取使用者輸入的檔案路徑 fn = FileName.Text; //建立XmlSerializer的對象引用Xs,並傳遞List<PersonDetail>的類型 XmlSerializer Xs = new XmlSerializer(typeof(List<PersonDetail>)); //建立Stream類型引用fs,並傳遞fn作路徑參數 Stream fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.None); //調用Xs的Serialize方法,傳遞fs和list參數 Xs.Serialize(fs, list); //關閉fs對象 fs.Close(); MessageBox.Show("XML序列化成功"); //將文字框控制項清空 nametxt.Text = ""; passwordtxt.Text = ""; FileName.Text = ""; } private void InputBtn_Click(object sender, EventArgs e) { string str; //擷取使用者輸入的檔案路徑 fn = ReadFileName.Text; try { //建立FileStream類型引用fs,並傳遞fn作路徑參數,檔案模式為開啟檔案 FileStream fs = new FileStream(fn, FileMode.Open); //建立XmlSerializer類型對象Xs,傳遞List<PersonDetail>的類型 XmlSerializer Xs = new XmlSerializer(typeof(List<PersonDetail>)); //調用Xs的Deserialize方法,傳遞fs //將返回的對象轉換為List<PersonDetail>類型,並將引用賦值給readlist readlist = (List<PersonDetail>)Xs.Deserialize(fs); //遍曆readlist的每個子項 foreach (PersonDetail Pd in readlist) { //將子項的屬性值組合後賦值給str變數 str = String.Format("姓名:【{0}】,密碼:【{1}】", Pd.Name, Pd.Password); //調用XmlList控制項Items的Add方法,將str添加為項 XmlList.Items.Add(str); } } //處理檔案未找到異常 catch (FileNotFoundException ex) { string msg = String.Format("異常資訊:{0}", ex.Message); MessageBox.Show(msg); } //將檔案路徑文字框控制項清空 ReadFileName.Text = ""; } } public class PersonDetail { //定義兩個私人欄位 string _name; string _password; //定義兩個公用屬性,可以讀寫相應的私人欄位 public string Name { get { return _name; } set { _name = value; } } public string Password { get { return _password; } set { _password = value; } } public PersonDetail() { } } } |
程式運行後,在前兩個"TextBox"控制項中輸入一組值並單擊"添加"按鈕,結果7.51所示。
使用者每單擊一次"添加"按鈕,list對象中將添加一個子項,該子項是根據使用者輸入值初始化的PersonDetail類的對象。當子項添加操作完成後,程式彈出7.51所示的資訊對話方塊。進行多次添加操作後,在Name屬性為"ReadFileName"的文字框控制項輸入任意XML檔案的檔案名稱,單擊"輸出XML"按鈕,即可完成XML格式的序列化操作。可將序列化操作建立的XML檔案名稱再次輸入到Name屬性為ReadFileName的文字框控制項中,然後單擊"XML還原序列化"按鈕即可完成該XML檔案中資料的還原序列化操作,運行結果7.52所示。
| |
| (點擊查看大圖)圖7.52 還原序列化XML檔案並輸出 |
根據輸入值,建立的list對象資料已經被成功還原序列化,並且在Name屬性為"XmlList"的列表框控制項中顯示。
解析
還原序列化是序列化的逆向操作,既然序列化操作需要寫入到流,還原序列化即讀取流並將對象資料提取出來。例如,在程式集相同目錄下有一個"Person.dat"檔案,該檔案以二進位格式持久化已知類型(如PersonName類)的對象,其還原序列化的方法如以下代碼所示:
//匯入BinaryFormatter類的命名空間 using System.Runtime.Serialization.Formatters.Binary; //建立BinaryFormatter類對象MyBF BinaryFormatter MyBF = new BinaryFormatter(); //建立FileStream 類型引用fs,讀取"Person.dat"檔案 FileStream fs = new FileStream("Person.dat", FileMode.Open); //調用MyBF的DeSerialize方法,傳遞fs參數 PersonName Pn = (PersonName)MyBF.DeSerialize(fs); //關閉fs對象 fs.Close(); |
以上代碼中,程式獲得了PersonName類對象的引用Pn,該對象根據"Person.dat"檔案還原序列化建立,還原原對象的資料。
面試例題22:如何自訂序列化?
考點:理解自訂序列化,學習自訂序列化方法。
出現頻率:★★★★
解答
在Visual Studio 2005/ Visual Studio 2008中建立一個C#的Windows表單應用程式項目,並將其項目命名為CustomSerialize。程式可以根據使用者輸入值建立一個對象,以二進位格式序列化對象,並持久化到指定的路徑。這個過程,對象的欄位值將被添加一段字串,並且其欄位值對應的鍵名也被修改為指定值,而不是欄位名稱。在還原序列化的過程中,對象的欄位資料值被修改為原始值,所以看上去對象資料沒有作任何修改。在Visual Studio 2005/Visual Studio 2008的"Form1.cs[設計]"視圖中建立基本的表單布局和控制項,控制項的命名7.53所示。
| |
| (點擊查看大圖)圖7.53 自訂序列化表單控制項布局及命名 |