The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

用 C# 撰寫序列化(Serialize)與反序列化(Deserialize) - Part 2

之前寫過一篇 如何用 C# 撰寫序列化(Serialize)與反序列化(Deserialize),最近正好又有專案用上,心想乾脆寫一個泛型的版本,讓以後所有專案都可以使用。

完整的程式碼如下:

using System.IO;
using System.Text;
using System.Xml.Serialization;
using System.Xml;

public static class SiteHelper
{
    public static string Serialize(object o)
    {
        XmlSerializer ser = new XmlSerializer(o.GetType());
        StringBuilder sb = new StringBuilder();
        StringWriter writer = new StringWriter(sb);
        ser.Serialize(writer, o);
        return sb.ToString();
    }

    public static T Deserialize<T>(string s)
    {
        XmlDocument xdoc = new XmlDocument();

        try
        {
            xdoc.LoadXml(s);
            XmlNodeReader reader = new XmlNodeReader(xdoc.DocumentElement);
            XmlSerializer ser = new XmlSerializer(typeof(T));
            object obj = ser.Deserialize(reader);

            return (T)obj;
        }
        catch
        {
            return default(T);
        }
    }
}

序列化(Serialize) 與 反序列化(Deserialize) 時的用法如下:

TestClass myObject = new TestClass { ID = "test"; };

// 將 myObject 物件序列化成 Xml 格式 (字串型態)
string s = SiteHelper.Serialize(myObject);

// 將 s 字串反序列化成 TestClass 型別的物件
TestClass o = SiteHelper.Deserialize<TestClass>(s);

---

在序列化的過程中其實並非所有物件都可以序列化,只要序列化失敗就會引發 Exception,但我的程式在寫「反序列化」已經做了 try/catch,所以只要反序列化失敗會直接回傳該型別的預設值 ( 只要是參考型別就會回傳 null ),在這裡我利用 C# 中的 default 關鍵字來取得應用泛型時物件的預設值。

像我在測試的過程中發現 System.Net.IPAddressSystem.Net.NetworkInformation.PhysicalAddress 這些型別都會無法進行序列化,錯誤訊息如下:

System.Net.NetworkInformation.PhysicalAddress cannot be serialized because it does not have a parameterless constructor.

解決的方法有兩種:

  1. 修改類別屬性,改用 string 型別儲存資料。
  2. 繼承無法序列化的型別,並實做 ISerializable 介面自訂序列化方法。

相關連結