1. 程式人生 > >XmlSerializer 物件的Xml序列化和反序列化

XmlSerializer 物件的Xml序列化和反序列化

這篇隨筆對應的.Net名稱空間是System.Xml.Serialization;文中的示例程式碼需要引用這個名稱空間。
為什麼要做序列化和反序列化?
.Net程式執行時,物件都駐留在記憶體中;記憶體中的物件如果需要傳遞給其他系統使用;或者在關機時需要儲存下來以便下次再次啟動程式使用就需要序列化和反序列化。
範圍:本文只介紹xml序列化,其實序列化可以是二進位制的序列化,也可以是其他格式的序列化。
看一段最簡單的Xml序列化程式碼
class Program
{
    static void Main(string[] args)
    {
        int i = 10;
        //宣告Xml序列化物件例項serializer
        XmlSerializer serializer = new XmlSerializer(typeof(int));
        //執行序列化並將序列化結果輸出到控制檯
        serializer.Serialize(Console.Out, i);
        Console.Read();
    }
}
上面程式碼對int i進行了序列化,並將序列化的結果輸出到了控制檯,輸出結果如下

<?xml version="1.0" encoding="gb2312"?>
<int>10</int>
可以將上述序列化的xml進行反序列化,如下程式碼
static void Main(string[] args)
{
    using (StringReader rdr = new StringReader(@"<?xml version=""1.0"" encoding=""gb2312""?>
<int>10</int>"))
    {
        //宣告序列化物件例項serializer
        XmlSerializer serializer = new XmlSerializer(typeof(int));
        //反序列化,並將反序列化結果值賦給變數i
        int i = (int)serializer.Deserialize(rdr);
        //輸出反序列化結果
        Console.WriteLine("i = " + i);
        Console.Read();
    }
}
以上程式碼用最簡單的方式說明了xml序列化和反序列化的過程,.Net系統類庫為我們做了大量的工作,序列化和反序列化都非常簡單。但是在現實中業務需求往往比較複雜,不可能只簡單的序列化一個int變數,顯示中我們需要對複雜型別進行可控制的序列化。

自定義物件的Xml序列化:

System.Xml.Serialization名稱空間中有一系列的特性類,用來控制複雜型別序列化的控制。例如XmlElementAttribute、XmlAttributeAttribute、XmlArrayAttribute、XmlArrayItemAttribute、XmlRootAttribute等等。

看一個小例子,有一個自定義類Cat,Cat類有三個屬性分別為Color,Saying,Speed。

namespace UseXmlSerialization
{
    class Program
    {
        static void Main(string[] args)
        {
            //宣告一個貓咪物件
            var c = new Cat { Color = "White", Speed = 10, Saying = "White or black,  so long as the cat can catch mice,  it is a good cat" };
 
            //序列化這個物件
            XmlSerializer serializer = new XmlSerializer(typeof(Cat));
 
            //將物件序列化輸出到控制檯
            serializer.Serialize(Console.Out, c);
 
            Console.Read();
        }
    }
 
    [XmlRoot("cat")]
    public class Cat
    {
        //定義Color屬性的序列化為cat節點的屬性
        [XmlAttribute("color")]
        public string Color { get; set; }
 
        //要求不序列化Speed屬性
        [XmlIgnore]
        public int Speed { get; set; }
 
        //設定Saying屬性序列化為Xml子元素
        [XmlElement("saying")]
        public string Saying { get; set; }
    }
}
可以使用XmlElement指定屬性序列化為子節點(預設情況會序列化為子節點);或者使用XmlAttribute特性制定屬性序列化為Xml節點的屬性;還可以通過XmlIgnore特性修飾要求序列化程式不序列化修飾屬性。

物件陣列的Xml序列化:

陣列的Xml序列化需要使用XmlArrayAttribute和XmlArrayItemAttribute;XmlArrayAttribute指定陣列元素的Xml節點名,XmlArrayItemAttribute指定陣列元素的Xml節點名。

如下程式碼示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
 
namespace UseXmlSerialization
{
    class Program
    {
        static void Main(string[] args)
        {
            //宣告一個貓咪物件
            var cWhite = new Cat { Color = "White", Speed = 10, Saying = "White or black,  so long as the cat can catch mice,  it is a good cat" };
            var cBlack = new Cat { Color = "Black", Speed = 10, Saying = "White or black,  so long as the cat can catch mice,  it is a good cat" };
 
            CatCollection cc = new CatCollection { Cats = new Cat[] { cWhite,cBlack} };
 
            //序列化這個物件
            XmlSerializer serializer = new XmlSerializer(typeof(CatCollection));
 
            //將物件序列化輸出到控制檯
            serializer.Serialize(Console.Out, cc);
 
            Console.Read();
        }
    }
 
    [XmlRoot("cats")]
    public class CatCollection
    {
        [XmlArray("items"),XmlArrayItem("item")]
        public Cat[] Cats { get; set; }
    }
 
    [XmlRoot("cat")]
    public class Cat
    {
        //定義Color屬性的序列化為cat節點的屬性
        [XmlAttribute("color")]
        public string Color { get; set; }
 
        //要求不序列化Speed屬性
        [XmlIgnore]
        public int Speed { get; set; }
 
        //設定Saying屬性序列化為Xml子元素
        [XmlElement("saying")]
        public string Saying { get; set; }
    }
}
以上程式碼將輸出:

<?xml version="1.0" encoding="gb2312"?>
<cats xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://ww
w.w3.org/2001/XMLSchema">
  <items>
    <item color="White">
      <saying>White or black,  so long as the cat can catch mice,  it is a good
cat</saying>
    </item>
    <item color="Black">
      <saying>White or black,  so long as the cat can catch mice,  it is a good
cat</saying>
    </item>
  </items>
</cats>
XmlSerializer記憶體洩漏問題:

多謝chenlulouis,仔細看了下msdn,確實存在洩漏的情況,msdn說明如下:

動態生成的程式集 

為了提高效能,XML 序列化基礎結構將動態生成程式集,以序列化和反序列化指定型別。此基礎結構將查詢並重復使用這些程式集。此行為僅在使用以下建構函式時發生: 

XmlSerializer(Type) 
XmlSerializer.XmlSerializer(Type, String) 

如果使用任何其他建構函式,則會生成同一程式集的多個版本,且絕不會被解除安裝,這將導致記憶體洩漏和效能降低。最簡單的解決方案是使用先前提到的兩個建構函式的其中一個。否則,必須在 Hashtable 中快取程式集,如以下示例中所示。

也就是說我們在使用XmlSerializer序列化,初始化XmlSerializer物件時最好使用下面兩個建構函式否則會引起記憶體洩漏。
XmlSerializer(Type)
XmlSerializer.XmlSerializer(Type, String)