C#之物件實例之序列化與反序列化

序列化有時候可以方便我們省下很多程式碼,又基於我目前所有的系統都是運行在非商用溝通的Web介面上,因此在這篇文章中我們討論的是「文字型XML序列化」、「二進制型序列化」,而「SOAP序列化」就不在我們討論的範圍了。

在開始之前一定要先請建立觀念,序列化只會序列實例(instances)的Public等級的成員,也就是Private等級的一律被忽略無視,因此如果你某一個實例裡面有用到Private等級的成員來保持某一種狀態,那麼就很抱歉了。此外,也不要認為在沒有任何可以Reference目標類別(DLL)的環境中,可以憑空的反序列化回來,這也是不可能的事。

序列化與反序列化依存的類別

  1. 文字型XML序列化 System.Xml.Serialization;
  2. 二進制型序列化 System.Runtime.Serialization.Formatters.Binary;

文字型XML序列化

程式碼如下,我們故意在裡面加入一個byte陣列,來測試二進制資料在序列化成文字之後,是否可以成功的被反序列化。另外我們也實作了一個private方法,來測試反序列化之後,是否可以順利的操作物件得到正確資料。要讓一個類別可以序列化,除了在上方加入[Serializable]描述之外,類別本身「一定要是Public」喔!

[Serializable]
public class People
{
  public string cFirstName { get; set; }
  public string cLastName { get; set; }
  public byte[] bytTest = { 0x41, 0x42 };  //A, B
  public string sayHello() { return processWords(); }
  private string processWords() { return string.Format("{0}, {1} says Hello!", cFirstName, cLastName);  }
}

class Program
{
  static void Main(string[] args)
  {
    People oPeople = new People() { cFirstName = "John", cLastName = "Lee" };
    System.Xml.Serialization.XmlSerializer oSerial = new System.Xml.Serialization.XmlSerializer(typeof(People));
    
    //序列化
    System.IO.StringWriter oStream = new System.IO.StringWriter();
    oSerial.Serialize(oStream, oPeople);
    oStream.Close();
    Console.WriteLine("序列化:");
    Console.WriteLine(oStream.ToString());

    //反序列化
    oPeople = (People)oSerial.Deserialize(new System.IO.StringReader(oStream.ToString()));
    Console.WriteLine("反序列化:");
    Console.WriteLine(oPeople.sayHello());
    Console.WriteLine("反序列化後之二進制資料測試:");
    Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(oPeople.bytTest));

    Console.Read();
  }
}

由上面的程式碼我們可以得知,序列化的過程中,必須寄宿在Stream裡面進行運作,這是合理的,因為大部分我們序列化後都是要寫到檔案或資料庫之中。另外我們也可以在VisualStudio運行過程中得知,二進制的序列化成文字之後,他其實會以Base64的機制來將二進制編碼起來。執行結果如下:

序列化:

<?xml version="1.0" encoding="utf-16"?>
<People xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <bytTest>QUI=</bytTest>
  <cFirstName>John</cFirstName>
  <cLastName>Lee</cLastName>
</People>

反序列化:

John, Lee says Hello!

反序列化後之二進制資料測試:

AB

二進制型序列化

二進制的序列化相對於文字型的序列化,變異不大,我們只要調用System.Runtime.Serialization.Formatters.Binary.BinaryFormatter類別來幫我們實作就可以了。由於他要求一定要System.IO.Stream抽象類別, 所以我們只好改換成System.IO.MemoryStream來實驗了。為了力求真實,我們把字串裡面的文字,由英文改成具備Unicode的中文,因此更可以反映反序列化後的正確性。

[Serializable]
public class People
{
  public string cFirstName { get; set; }
  public string cLastName { get; set; }
  public byte[] bytTest = { 0x41, 0x42 };
  public string sayHello() { return processWords(); }
  private string processWords() { return string.Format("{0}, {1} says Hello!", cFirstName, cLastName);  }
}

class Program
{
  static void Main(string[] args)
  {
    People oPeople = new People() { cFirstName = "錫堃", cLastName = "游" };
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter oSerial = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

    //序列化
    System.IO.MemoryStream oStream = new System.IO.MemoryStream();
    oSerial.Serialize(oStream, oPeople);
    oStream.Close();
    Console.WriteLine("序列化:");
    byte[] bytTemp = oStream.ToArray();
    Console.WriteLine(System.Text.ASCIIEncoding.UTF8.GetString(bytTemp));

    //反序列化
    oPeople = (People)oSerial.Deserialize(new System.IO.MemoryStream(bytTemp));
    Console.WriteLine("反序列化:");
    Console.WriteLine(oPeople.sayHello());
    Console.WriteLine("反序列化後之二進制資料測試:");
    Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(oPeople.bytTest));

    Console.Read();
  }
}

經過上面的程式碼我們發現是正確的運行的,我們勉強地把二進制資料轉換成文字印在Big5等級的Console上,想當然爾會出現一堆亂碼,不過可以確定的是,所有資料的反序列化回來後,都是正確的資料。

.NET C# Object Serialize Serializable Deserialize Deserializable