C#序列化(Serialize)、反序列化(Deserialize)

序列化

序列化又稱串行化,是.NET運行時環境用來支持用户定義類型的流化的機制。其目的是以某種存儲形成使自定義對象持久化,或者將這種對象從一個地方傳輸到另一個地方。

    .NET框架提供了兩種串行化的方式:

1、是使用BinaryFormatter進行串行化;

2、使用SoapFormatter進行串行化;

3、使用XmlSerializer進行串行化。

第一種方式提供了一個簡單的二進制數據流以及某些附加的類型信息,

而第二種將數據流格式化為XML存儲;

第三種其實和第二種差不多也是XML的格式存儲,只不過比第二種的XML格式要簡化很多(去掉了SOAP特有的額外信息)。

[Serializable]屬性將類標誌為可序列化的。如果某個類的元素不想被序列化,1、2可以使用[NonSerialized]屬性來標誌,2、可以使用[XmlIgnore]來標誌。

1、使用BinaryFormatter進行串行化

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
    public class ClassToSerialize
    {
        public int id = 100;
        public string name = "Name";
        [NonSerialized] //不會被序列化
        public string Sex = "男";
    }
public static void SerializeNow()
        {
            ClassToSerialize c = new ClassToSerialize();
            FileStream fileStream = new FileStream("c:\\temp.dat", FileMode.Create);
            BinaryFormatter b = new BinaryFormatter();
            b.Serialize(fileStream, c);
            fileStream.Close();
        }

        public static void DeSerializeNow()
        {
            ClassToSerialize c = new ClassToSerialize();
            c.Sex = "kkkk";
            FileStream fileStream = new FileStream("c:\\temp.dat", FileMode.Open, FileAccess.Read, FileShare.Read);
            BinaryFormatter b = new BinaryFormatter();
            c = b.Deserialize(fileStream) as ClassToSerialize;
            Console.WriteLine(c.name);
            Console.WriteLine(c.Sex);
            fileStream.Close();
        }

Sex屬性因為被標誌為[NonSerialized],故其值總是為null。

2、使用SoapFormatter進行串行化

using System.Runtime.Serialization.Formatters.Soap; //引入System.Runtime.Serialization.Formatters.Soap類庫
public static void SOAPSerializeNow()
        {
            ClassToSerialize c = new ClassToSerialize();
            FileStream fileStream = new FileStream("c:\\temp.xml", FileMode.Create);
            SoapFormatter soap = new SoapFormatter();
            soap.Serialize(fileStream,c);
            fileStream.Close();
        }

        public static void SOAPDeSerializeNow()
        {
            ClassToSerialize c = new ClassToSerialize();
            c.Sex = "kkkk";
            FileStream fileStream = new FileStream("c:\\temp.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
            SoapFormatter soap = new SoapFormatter();
            c = soap.Deserialize(fileStream) as ClassToSerialize;
            Console.WriteLine(c.name);
            Console.WriteLine(c.Sex);
            fileStream.Close();
        }


結果:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:ClassToSerialize id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/ConsoleApplication1/ConsoleApplication1%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<id>100</id>
<name id="ref-3">Name</name>
</a1:ClassToSerialize>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>


3、使用XmlSerializer進行串行化


[Serializable]
    public class Person
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
        public Course[] Courses { get; set; }

        public Person()
        {

        }

        public Person(string name)
        {
            this.Name = name;
            this.Sex = "男";
        }
    }

    [Serializable]
    public class Course{
        public string Name { get; set; }
        [XmlIgnore]
        public string Description { get; set; }
        public Course()
        {

        }
        public Course(string name,string description)
        {
            this.Name = name;
            this.Description = description;
        }
    }


public static void XMLSerializeNow()
        {
            Person c = new Person("cyj");
            c.Courses = new Course[2];
            c.Courses[0] = new Course("英語","交流工具");
            c.Courses[1] = new Course("數學","自然科學");
            XmlSerializer xs = new XmlSerializer(typeof(Person));
            FileStream fileStream = new FileStream("c:\\cyj.xml", FileMode.Create, FileAccess.Write, FileShare.Read);
            xs.Serialize(fileStream,c);
            fileStream.Close();
        }

        public static void XMLDeSerializeNow()
        {
            XmlSerializer xs = new XmlSerializer(typeof(Person));
            FileStream fileStream = new FileStream("c:\\cyj.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
            Person p = xs.Deserialize(fileStream) as Person;
            Console.WriteLine(p.Name);
            Console.WriteLine(p.Age.ToString());
            Console.WriteLine(p.Courses[0].Name);
            Console.WriteLine(p.Courses[0].Description);
            Console.WriteLine(p.Courses[1].Name);
            Console.WriteLine(p.Courses[1].Description);
            fileStream.Close();
        }

這裏Course類的Description屬性值將始終為null,生成的xml文檔中也沒有該節點,如下圖:

<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>cyj</Name>
  <Sex>男</Sex>
  <Age>0</Age>
  <Courses>
    <Course>
      <Name>英語</Name>
    </Course>
    <Course>
      <Name>數學</Name>
    </Course>
  </Courses>
</Person>


4、自定義序列化

如果你希望讓用户對類進行串行化,但是對數據流的組織方式不完全滿意,那麼可以通過在自定義類中實現接口來自定義串行化行為。這個接口只有一個方法,GetObjectData. 這個方法用於將對類對象進行串行化所需要的數據填進SerializationInfo對象。你使用的格式化器將構造SerializationInfo對象,然後在串行化時調用GetObjectData. 如果類的父類也實現了ISerializable,那麼應該調用GetObjectData的父類實現。
    如果你實現了ISerializable,那麼還必須提供一個具有特定原型的構造器,這個構造器的參數列表必須與GetObjectData相同。這個構造器應該被聲明為私有的或受保護的,以防止粗心的開發人員直接使用它。
    示例如下:
    實現ISerializable的類:

[Serializable]
    public class Employee : ISerializable
    {
        public int EmpId = 100;
        public string EmpNam = "aaaa";
        [NonSerialized]
        public string NoSerialString = "NoSerialString-Test";
        public Employee()
        {
            //
            // TODO: 在此處添加構造函數邏輯
            //
        }

        public Employee(SerializationInfo info,StreamingContext ctx)
        {
            EmpId = (int)info.GetValue("EmployeeId", typeof(int));
            EmpNam = (String)info.GetValue("EmployeeName", typeof(string));
            //NoSerialString = (String)info.GetValue("EmployeeString",typeof(string));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("EmployeeId", EmpId);
            info.AddValue("EmployeeName",EmpNam);
            //info.AddValue("EmployeeString", NoSerialString);
        }
    }


public static void OtherEmployeeClassTest()
        {
            Employee mp = new Employee();
            mp.EmpId = 10;
            mp.EmpNam = "abc";
            mp.NoSerialString = "Hello";
            Stream stream = File.Open("c:\\temp3.dat",FileMode.Create);
            BinaryFormatter bf = new BinaryFormatter();
            Console.WriteLine("Writing Employee Info;");
            bf.Serialize(stream,mp);
            stream.Close();
            //反序列化
            Stream stream1 = File.Open("c:\\temp3.dat", FileMode.Open);
            BinaryFormatter bf2 = new BinaryFormatter();
            Console.WriteLine("Reading Employee Info;");
            Employee mp2 = (Employee)bf2.Deserialize(stream1);
            stream1.Close();
            Console.WriteLine(mp2.EmpId);
            Console.WriteLine(mp2.EmpNam);
            Console.WriteLine(mp2.NoSerialString);
        }


結束

趕緊學習為了早點面試找到工作,加油!