對象通常都有狀態(state),從一個對象中抽取這種狀態,不論是將它存儲於某地,還是通過網絡傳送,這種抽取動作稱為“將一個對象序列化”,而反向處理過程,從一個被序列化的狀態重建一個對象即為反序列化。
序列化工作系由一個特定的格式化器(formatter)完成,每個格式化器都提供Serialize和Deserialize兩個方法。當格式化器將某個對象序列化后,所得好結果被放入一個流(Stream)中,(所謂的流是字節序列的一個抽象概念)因此可以包容任何序列化格式。一對象被存儲於一個流之中,對象的狀態好久可以被存儲於磁盤上(或者說被持久化(persistent))
對於一個可被序列化的類型,只需要給他表上[Serializable]特性,也可以只賦給某個特定的字段
NonSerialized 指明被標記的字段不可序列化
下面是自己練習的示例:
1.二進制序列化
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading.Tasks; namespace SerializableTest { public class Program { static void Main(string[] args) { Goods good = new Goods(); good.name = "蘋果"; good.price = 10; good.type = "水果"; string dir = System.AppDomain.CurrentDomain.BaseDirectory; //序列化 IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream(dir+"test.bin", FileMode.Create, FileAccess.Write); formatter.Serialize(stream, good); stream.Close();//必須關閉 //反序列化 IFormatter reformatter = new BinaryFormatter(); Stream filestream = new FileStream(dir+"test.bin", FileMode.Open, FileAccess.Read); //返回Object類型,必須強制轉換 Goods newgood = (Goods)reformatter.Deserialize(filestream); Console.WriteLine(newgood.name); Console.WriteLine(newgood.price); Console.WriteLine(newgood.type); Console.ReadLine(); } } [Serializable] public class Goods { /// <summary> /// 名稱 /// </summary> public string name { get; set; } /// <summary> /// 價格 /// </summary> public double price { get; set; } /// <summary> /// 分類 /// </summary> public string type { get; set; } } }
上例使用二進制格式化器BinaryFormatter:System.Runtime.Serialization.Formatters.Binary;
注:Iformatter接口序列化對象時,只需要提供了Stream流對象就行了。將對象序列化到文件流(FileStream)、內存流(MemoryStream)、網絡流(NetworkStream)都可以。
在測試 特新NonSerialized 時出現了點問題:“特性“NonSerialized”對此聲明類型無效。它只對“field”聲明有效”
由於C#3.0 的新特性get/set訪問器,在編譯的時候,編譯器會自動為你生成對應的私有變量,變量名自動生成。
因此考慮 直接顯示聲明私有屬性 private int number,並標注[NonSerialized]特性。
運行結果:
2.XML序列化
XML序列化,對象被以XML格式保存,XML序列化常常用在Web服務項目里(最近的項目里看到有模塊用到,所以自己學習一下)
System.Xml.Serialization命名空間:含有使用XML序列化所需要的類和功能
XmlSerializer類,提供序列化Serialeze()和反序列話Deserialize()方法。
XmlIgnore屬性,讓XmlSerializer類跳過不序列化的成員(XML序列化 Serializable和NoSerialized屬性將被忽略,而是使用XmlIgnore屬性,它的作用與NoSerialized類似)
例如:
/// <summary>
/// 分類
/// </summary>
[XmlIgnore]
public string type { get; set; }
Goods good = new Goods(); good.name = "蘋果"; good.price = 10; good.type = "水果"; good.Number = 12; string dir = System.AppDomain.CurrentDomain.BaseDirectory; //序列化 XmlSerializer formatter = new XmlSerializer(typeof(Goods)); FileStream stream = new FileStream(dir + "test.bin", FileMode.Create, FileAccess.Write); formatter.Serialize(stream, good); stream.Close();//必須關閉 //反序列化 XmlSerializer reformatter = new XmlSerializer(typeof(Goods)); FileStream filestream = new FileStream(dir + "test.bin", FileMode.Open, FileAccess.Read); //返回Object類型,必須強制轉換 Goods newgood = (Goods)reformatter.Deserialize(filestream); Console.WriteLine("名稱:" + newgood.name); Console.WriteLine("價格:" + newgood.price); Console.WriteLine("種類:" + newgood.type); Console.WriteLine("數量:" + newgood.Number); Console.ReadLine();
持久化后的XML數據
<?xml version="1.0"?> <Goods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <name>蘋果</name> <price>10</price> <Number>12</Number> </Goods>
可以發現加了[XmlIgnore]特性的type字段沒有被序列化
注:public int Number被序列化了,private int number 沒有被序列化,據說XML序列化 private類型字段不能被序列化,且元素的屬性必須為讀/寫屬性。