C# 70-536 – Chapter 5 Serialization

  • 4149
  • 0
  • C#
  • 2011-05-11

C# 70-536 – Chapter 5

「序列化(Serialization)」:將物件狀態轉換為可保存或可傳輸格式的處理序。序列化的反面是還原序列化,它可以將資料流轉換成物件。

BinaryFormatter:最有效率的序列化,只能讓.NET Framework的程式讀取。

SoapFormatter:以SOAP 格式序列化和還原序列化物件,需要額外加入參考(System.Runtime.Serialization.Formatters.Soap.dll)。

XML 序列化:以XML格式進行序列化,和各種平台相容性最高,但只能序列化公開資料(Public Data),且不能序列化圖形物件。

使用BinaryFormatter進行序列化:

string fPath = @"D:\serial.data";
FileStream fs = new FileStream(fPath, FileMode.OpenOrCreate);


BinaryFormatter bf = new BinaryFormatter();
//Binary序列化
bf.Serialize(fs, DateTime.Now);

fs.Position = 0; //重讀

//反序列化
DateTime dt = (DateTime)bf.Deserialize(fs);

fs.Close();
if (dt != null)
	Console.WriteLine(dt.ToLongTimeString());

建立可被BinaryFormatter序列化的類別:

使用SerializableAttribute,不需要序列化的成員則註記NonSerializedAttribute,例:暫存或是計算出來的值,可在還原序列化時再處理。可使用IDeserializationCallback,實作IDeserializationCallback.OnDeserialization,或是使用OnDeserializedAttribute(Soap序列化不支援事件屬性)。

**序列化會有版本相容性問題,所以要特別注意

 

[Serializable]
class ShoppingCartItem
{
	#region prop
	private int _productId;

	public int ProductId
	{
		get { return _productId; }
		set { _productId = value; }
	}

	private decimal _price;

	public decimal Price
	{
		get { return _price; }
		set { _price = value; }
	}
	private int _quantity;

	public int Quantity
	{
		get { return _quantity; }
		set { _quantity = value; }
	}

	[NonSerialized] //不需序列化
	private decimal _total;

	public decimal Total
	{
		get { return _total; }
	}

	[OptionalField] //在序列化時可忽略的欄位(相容性處理)
	private bool _taxable;

	public bool Taxable
	{
		get { return _taxable; }
		set { _taxable = value; }
	}


	#endregion


	public ShoppingCartItem(int productId, decimal price, int quantity)
	{
		_productId = productId;
		_price = price;
		_quantity = quantity;
		_total = price * quantity;
	}

}

還原處理:

//二擇一

//實作IDeserializationCallback
void IDeserializationCallback.OnDeserialization(Object sender)
{
	_total = _price * _quantity;
}

//使用OnDeserializedAttribute
[OnDeserializedAttribute]
internal void OnDeserialization(StreamingContext context)
{
	_total = _price * _quantity;
}

建立可被XML序列化的類別:

1.類別必需為public

2.要序列化的成員也必需為public

3.沒有參數的建構式

若要自訂XML序列化,則需實作IXmlSerializable。

[XmlRoot("CartItem")]
public class ShoppingCartItem : IXmlSerializable
{
	#region prop
	private int _productId;

	[System.Xml.Serialization.XmlAttribute]
	public int ProductId
	{
		get { return _productId; }
		set { _productId = value; }
	}

	private decimal _price;

	public decimal Price
	{
		get { return _price; }
		set { _price = value; }
	}
	private int _quantity;

	public int Quantity
	{
		get { return _quantity; }
		set { _quantity = value; }
	}

	private decimal _total;

	[XmlIgnore]
	public decimal Total
	{
		get { return _total; }
	}

	#endregion


	//xml序列化一定要一個不帶參數的建構式
	public ShoppingCartItem()
	{
		
	}

	public ShoppingCartItem(int productId, decimal price, int quantity)
	{
		_productId = productId;
		_price = price;
		_quantity = quantity;
		_total = price * quantity;
	}

}

自訂XML序列化:

**GetSchema可以不必實作。

#region IXmlSerializable 自訂序列化

System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
	return null;
}

void IXmlSerializable.ReadXml(XmlReader reader)
{
	XmlDocument doc = new XmlDocument();
	doc.Load(reader);

	_price = Convert.ToDecimal(doc.SelectSingleNode("CartItem/Price").InnerText);
	_quantity = Convert.ToInt32(doc.SelectSingleNode("CartItem/Quantity").InnerText);
	_productId =Convert.ToInt32( doc.DocumentElement.Attributes["ProductId"].Value);
	_total = _price * _quantity;
}

void IXmlSerializable.WriteXml(XmlWriter writer)
{
	writer.WriteStartAttribute("ProductId"); //Attribute "Name"            
	writer.WriteString(_productId.ToString()); //Attribute Value             
	writer.WriteEndAttribute();
	writer.WriteStartElement("Price");
	writer.WriteString(_price.ToString());
	writer.WriteEndElement();
	writer.WriteStartElement("Quantity");
	writer.WriteString(_quantity.ToString());
	writer.WriteEndElement();
}

#endregion

自訂序列化:實作ISerializable,必須實作GetObjectData方法,及還原序列化時使用的特殊建構函式。

StreamingContext:提供序列化目的端的相關資訊

SerializationInfo:執行序列化及反序列化的動作,實作IFormatterConverter。

//for deserialization
protected ShoppingCartItem(SerializationInfo info, StreamingContext context)
{
}

#region ISerializable 成員

void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{	
}

#endregion

序列化及反序列化順序:

serialization

 

Dotblogs 的標籤: