C#對象序列化(1)作者: 日期:2009-3-14 23:41:49 出處:淘特網
對象序列化在應聘過程中並不常見,但是在實際應用中卻是很常見的。本節將列舉3個比較典型的問題,以擴充.Net的相關知識面。
面試例題20:編寫對象序列化的程式。
考點:掌握對象序列化的基本方法,理解序列化中不同格式的區別。
出現頻率:★★★
解答
在Visual Studio 2005/Visual Studio 2008中創個C#的Windows表單應用程式項目,並將其項目命名為MultiSerialize。程式使用5個"TextBox"控制項分別接受使用者的輸入,其中上面4個控制項用於傳遞相應的值給某個對象,而下面的"TextBox"控制項用於隱藏檔名。當使用者單擊"TextBox"操作下面的3個按鈕控制項中任意一個時,程式將根據使用者輸入值初始化一組對象,並將對象圖進行相應格式的序列化。在Visual Studio 2005/ Visual Studio 2008的"Form1.cs[設計]"視圖中建立基本的表單布局和控制項,控制項的命名7.43所示。
在編寫代碼前,先引用System.Runtime.Serialization. Formatters.Soap.dll程式集,即單擊Visual Studio 2005/ Visual Studio 2008功能表列的"項目|添加引用"命令,在".NET"選項卡中找到所需要的程式集,單擊"確定"按鈕,即完成了外部程式集的引用操作,結果 7.44所示。
分別雙擊Form1的3個按鈕控制項,編寫相應的"Click"事件處理方法。MultiSerialize項目的Form1.cs如代碼7.25所示。
代碼7.25 序列化對象:Form1.cs
using System; ……………………………………… //匯入必要的命名空間 using System.Xml.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Soap; using System.Runtime.Serialization; using System.IO; namespace MultiSerialize { public partial class Form1 : Form { //聲明string類型變數,用於方法中儲存使用者輸入值 string n, nn, p, m, fn, Success; public Form1() { InitializeComponent(); } private void XmlBtn_Click(object sender, EventArgs e) { //將使用者輸入值賦值給變數 n = this.Nm.Text; nn = this.NNm.Text; p = this.Pwd.Text; m = this.Msg.Text; fn = this.FileName.Text; //定義成功資訊 Success = "XML輸出成功"; //建立PersonName的對象引用Pn,並傳遞4個變數 PersonName Pn = new PersonName(n, nn, p, m); //建立XmlSerializer的對象引用Xs,並傳遞型別參數 XmlSerializer Xs = new XmlSerializer(typeof(PersonName), new Type[] { typeof(PersonOther) }); //建立Stream類型引用fs,並傳遞fn作路徑參數 Stream fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.None); //調用Xs的Serialize方法,傳遞fs和Pn參數 Xs.Serialize(fs, Pn); //關閉fs對象 fs.Close(); //輸出成功資訊 MessageBox.Show(Success); } private void BinBtn_Click(object sender, EventArgs e) { //建立IFormatter介面引用,來自於BinaryFormatter類對象 IFormatter Fmt = new BinaryFormatter(); //定義成功資訊 Success = "二進位輸出成功"; //調用UseIFormatter方法,並傳遞Fmt和Success參數 UseIFormatter(Fmt, Success); } private void SoapBtn_Click(object sender, EventArgs e) { //建立IFormatter介面引用,來自於SoapFormatter類對象 IFormatter Fmt = new SoapFormatter(); //定義成功資訊 Success = "Soap輸出成功"; //調用UseIFormatter方法,並傳遞Fmt和Success參數 UseIFormatter(Fmt, Success); } //定義UseIFormatter方法,接收一個IFormatter型別參數 void UseIFormatter(IFormatter Fmt, string Success) { //將使用者輸入值賦值給變數 n = this.Nm.Text; nn = this.NNm.Text; p = this.Pwd.Text; m = this.Msg.Text; fn = this.FileName.Text; //建立PersonName的對象引用Pn,並傳遞4個變數 PersonName Pn = new PersonName(n, nn, p, m); //建立Stream類型引用fs,並傳遞fn作路徑參數 Stream fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.None); //調用Fmt的Serialize方法,傳遞fs和Pn參數 Fmt.Serialize(fs, Pn); //關閉fs對象 fs.Close(); //輸出成功資訊 MessageBox.Show(Success); } } //定義PersonName類,並標記可序列化特性 [Serializable] public class PersonName { public string _name; //標記不可序列化特性 [NonSerialized] public string _nickname; //建立PersonOther類型的對象Po public PersonOther Po = new PersonOther(); public PersonName() { } //重載建構函式,接收4個string型別參數 public PersonName(string n,string nn, string p, string m) { //賦值給欄位 this._name = n; this._nickname = nn; //賦值給Po對象的兩個屬性 this.Po.Password = p; this.Po.Message = m; } } //定義PersonOther類,並標記可序列化特性 [Serializable] public class PersonOther { //定義2個私人欄位 string _password; string _message; //定義兩個公用屬性,可以讀寫相應的私人欄位 public string Password { get { return _password; } set { _password = value; } } public string Message { get { return _message; } set { _message = value; } } public PersonOther() { } } } |
程式運行時,可以向前4個"TextBox"控制項填入某人的基本資料,然後在Name屬性為"FileName"控制項中填入"Person.dat",即輸出檔案的檔案名稱,運行結果7.45所示。
當使用者單擊"二進位格式"按鈕後,程式將根據使用者輸入的值建立並初始化1個PersonName類的對象。程式使用二進位格式序列化該對象並輸出到程式集相同目錄下的Person.dat檔案中,當完成了這些工作,程式將使用資訊對話方塊提示序列化操作成功,運行結果7.46所示。
在圖7.47中,編譯完成的MultiSerialize程式集相同目錄下已經建立了Person.dat檔案,並且程式也跳出了資訊對話方塊,並提示操作成功。如果按下"Soap格式"按鈕或"XML格式"按鈕,其運行結果是相似的,但是建議其組建檔案的副檔名應分別修改為對應的"soap"和"xml"。假設使用者已經產生了3種不同格式的檔案,對象資料通過序列化操作持久化到檔案中了。用Visual Studio 2005/Visual Studio 2008開啟"Person.dat"檔案7.47所示。
| |
| (點擊查看大圖)圖7.47 "Person.dat"檔案內容 |
其中中文部分無法正常顯示,但是數字是可以正常顯示,這是因為Name屬性中"Pwd"的控制項的值是數字(即圖中的"1900")。在程式運行時填入英文,同樣可以正常顯示。從"Person.dat"檔案的內容中可以看出,二進位格式儲存了比較完整的對象資訊,如所屬程式集,程式集版本等資訊,有利於以後還原對象資料。用Visual Studio 2005/Visual Studio 2008開啟"Person.soap"檔案,結果7.48所示。
| |
| (點擊查看大圖)圖7.48 "Person.soap"檔案內容 |
從圖7.48中可看到_nickname欄位並沒有被持久化,因為該欄位在Person類中定義時標記了[NonSerialized]特性,即不可序列化。相應地,用Visual Studio 2005/ Visual Studio 2008開啟"Person.xml"檔案,結果7.49所示
| |
| (點擊查看大圖)圖7.49 "Person.xml"檔案內容 |
說明:項目所產生的程式集路徑為"項目路徑\bin\debug"。
如果修改程式的代碼,可知二進位格式序列化的檔案除了儲存程式集的資訊,還儲存私人欄位及公用欄位的資料SOAP格式和XML格式僅儲存對象的公用欄位及公用屬性,但是這兩種格式可以應用於更大範圍的平台、應用程式架構中。並且XML格式所序列化的對象資料包含了被標記為 [NonSerialized]特性的欄位。
說明:本題程式採用IFormatter介面實現多態的應用,使二進位格式化和SOAP格式化操作重用了部分的代碼。程式中使用IFormatter介面必須匯入其命名空間,即System.Runtime.Serialization。