和BinaryFormatter序列化一樣,做一個可以序列化的類Person:
namespace Serializable
{
[Serializable] //不可少!
public class Person
{
private String name;
private String sex;
private int age;
public Person() //XmlSerializer序列化要求一定要有無參數構造函數
{
name = "";
sex = "";
age = 0;
}
public Person(String n, String s, int a)
{
name = n;
sex = s;
age = a;
}
public String Name
{
get
{
return name;
}
set
{
name = value;
}
}
public String Sex
{
get
{
return sex;
}
set
{
sex = value;
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
}
}
//主運行程序
namespace Serializable
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Person("張三", "男", 20);
//序列化
try
{
FileStream fs = new FileStream("serialiable.xml", FileMode.Create);
XmlSerializer xs = new XmlSerializer(typeof(Person));
xs.Serialize(fs, p1);
fs.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("序列化成功!");
Console.Read();
//反序列化
try
{
FileStream fs = new FileStream("serialiable.xml", FileMode.Open, FileAccess.Read);
XmlSerializer xs = new XmlSerializer(typeof(Person));
Person p = (Person)xs.Deserialize(fs);
Console.WriteLine(p.Name + p.Sex + p.Age);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.Read();
Console.Read();
}
}
}
結果圖:
生成的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();
- }
- }
- []
- public class Cat
- {
- //定義Color屬性的序列化爲cat節點的屬性
- []
- public string Color { get; set; }
- //要求不序列化Speed屬性
- []
- public int Speed { get; set; }
- //設置Saying屬性序列化爲Xml子元素
- []
- 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();
- }
- }
- []
- public class CatCollection
- {
- []
- public Cat[] Cats { get; set; }
- }
- []
- public class Cat
- {
- //定義Color屬性的序列化爲cat節點的屬性
- []
- public string Color { get; set; }
- //要求不序列化Speed屬性
- []
- public int Speed { get; set; }
- //設置Saying屬性序列化爲Xml子元素
- []
- 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內存泄漏問題:
- 仔細看了下msdn,確實存在泄漏的情況,msdn說明如下:
- 動態生成的程序集
- 爲了提高性能,XML 序列化基礎結構將動態生成程序集,以序列化和反序列化指定類型。此基礎結構將查找並重複使用這些程序集。此行爲僅在使用以下構造函數時發生:
- XmlSerializer(Type)
- XmlSerializer.XmlSerializer(Type, String)
- 如果使用任何其他構造函數,則會生成同一程序集的多個版本,且絕不會被卸載,這將導致內存泄漏和性能降低。最簡單的解決方案是使用先前提到的兩個構造函數的其中一個。否則,必須在 Hashtable 中緩存程序集,如以下示例中所示。
- 也就是說我們在使用XmlSerializer序列化,初始化XmlSerializer對象時最好使用下面兩個構造函數否則會引起內存泄漏。
- XmlSerializer(Type)
- XmlSerializer.XmlSerializer(Type, String)