引言
程序員在編寫應用程序的時候往往要將程序的某些數據存儲在內存中,然後將其寫入某個文件或是將它傳輸到網絡中的另一臺計算機上以實現通訊。這個將程序數據轉化成能被存儲並傳輸的格式的過程被稱爲”序列化”(Serialization),而它的逆過程則可被稱爲”反序列化”(Deserialization)。通俗上講,假如程序在運行的時候,內存中有一個對象,如果你想把這個對象的某些信息或者所有信息保存在本地,下次程序打開後,能夠直接還原這個對象,怎麼才能做到呢?
.Net框架對序列化機制具有非常好的支持,常用的爲
二進制格式器(Binary Formatter) 、 XML格式器(XML Formatter)
不過在實際的應用中,二進制格式器往往應用於一般的桌面程序和網絡通訊程序中,而XML格式器稟承了XML技術的優點,大多數被應用於.Net Remoting和XML Web服務等領域。下面我們來分析一下兩種格式器各自的優點。
xml序列化
使用XML序列化或反序列化時,需要對XML序列化器指定需要序列化對象的類型和其關聯的類型。
XML序列化只能序列化對象的公有屬性,並且要求對象有一個無參的構造方法,否者無法反序列化。
[Serializable]和[NonSerialized]特性對XML序列化無效!所以使用XML序列化時不需要對對象增加[Serializable]特性。
public class Person
{
public string Name;//姓名
public bool Sex;//性別,是否是男
public Person() { }//必須提供無參構造器,否則XmlSerializer將出錯
public Person(string name, bool sex)
{
this.Name = name;
this.Sex = sex;
}
public override string ToString()
{
return "姓名:" + this.Name + "\t性別:" + (this.Sex ? "男" : "女");
}
/// <summary>
/// 對象序列化成 XML String
/// </summary>
public string XmlSerialize<T>(T obj)
{
string xmlString = string.Empty;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
xmlSerializer.Serialize(ms, obj);
xmlString = Encoding.UTF8.GetString(ms.ToArray());
}
return xmlString;
}
// <summary>
/// XML String 反序列化成對象
/// </summary>
public T XmlDeserialize<T>(string xmlString)
{
T t = default(T);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
//此處用的是MemoryStream
using (Stream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
{
using (XmlReader xmlReader = XmlReader.Create(xmlStream))
{
Object obj = xmlSerializer.Deserialize(xmlReader);
t = (T)obj;
}
}
return t;
}
二進制序列化
使用二進制序列化,必須爲每一個要序列化的的類和其關聯的類加上[Serializable]特性,對類中不需要序列化的成員可以使用[NonSerialized]特性。
二進制序列化對象時,能序列化類的所有成員(包括私有的),且不需要類有無參數的構造方法。
使用二進制格式序列化時,它不僅是將對象的字段數據進行持久化,也持久化每個類型的完全限定名稱和定義程序集的完整名稱(包括包稱、版本、公鑰標記、區域性),這些數據使得在進行二進制格式反序列化時亦會進行類型檢查。所以反序列化時的運行環境要與序列化時的運行環境要相同,要記得添加引用,否者可能會無法反序列化成功。
[Serializable] //特性,當爲某個類加了該特性後,這個類就標記爲了可序列化的了。
public class Person : Animal
{
private Car _myCar;
public Car MyCar
{
get { return _myCar; }
set { _myCar = value; }
}
//[NonSerialized]//當前這個字段就不會被序列化了。
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
二進制序列化要求:
1.被序列化的對象的類型必須標記爲可序列化的。
2.二進制序列化會把屬性對應的字段序列化到文件中,所以最好類型中不要使用自動屬性(編譯器會自動生成字段),而要自己寫屬性與字段
3.當序列化一個對象的時候,這個對象本身以及的所有父類都必須標記爲可序列化的。
4.類型中所有屬性與字段的類型必須也標記爲可序列化的。接口不需要。
5.通過[NonSerialized]把某個字段標記爲不可序列化的。
Person person = new Person();
person.Name = "張三";
person.Age = 19;
person.Email = "[email protected]";
person.MyCar = new Car() { Brand = "時風" };
//二進制序列化步驟:
//1.創建二進制序列化器
BinaryFormatter bf = new BinaryFormatter();
//我們希望將對象序列化到一個文件上,所以要創建一個文件流
using (FileStream fsWrite = File.OpenWrite("person.bin"))
{
//開始執行二進制序列化
bf.Serialize(fsWrite, person);
}
Console.WriteLine("序列化完畢!");
Console.ReadKey();
反序列化的時候,需要創建原來被序列化的類型的對象,所以反序列化的時候需要引用被序列化的類型的對象。正是因爲如此,所以在二進制序列化的時候,那些屬性名、方法等根本不需要序列化,只需要把那些狀態信息(數據→字段的值)序列化了就好了,對於那些方法等信息,在反序列化時,創建對象的時候會自動創建,然後根據序列化文件中的字段的值,進行賦值。