C# 序列化和反序列化


C#序列化詳解

 
 

  程序員在編寫應用程序的時候往往要將程序的某些數據存儲在內存中,然后將其寫入某個文件或是將它傳輸到網絡中的另一台計算機上以實現通訊。這個將程序數據轉化成能被存儲並傳輸的格式的過程被稱為"序列化"(Serialization),而它的逆過程則可被稱為"反序列化"(Deserialization)。

 

  .Net框架對序列化機制具有非常好的支持,它提供了兩個名字空間(namespace):System.Runtime.Serialization和System.Runtime.Serialization.Formatters以完成序列化機制的大部分功能。系列化這項技術可以應用在將程序產生的結果數據存儲到文件系統中,但是它更主要的應用是在於.Net Remoting和Web服務的實現上。

 

  序列化機制的實現是依靠格式器(Formatter)而完成的,它是一個從System.Runtime.Serialization.IFormatter繼承下來的類的對象。格式器完成了將程序數據轉化到能被存儲並傳輸的格式的工作,同時也完成了將數據轉化回來的工作。.Net框架為程序員提供了兩種類型的格式器,一種通常是應用於桌面類型的應用程序的,它一個是System.Runtime.Serialization.Formatters.Binary.BinaryFormatter類的對象,而另一種則更主要的應用於.Net Remoting和XML Web服務等領域的,它一個是System.Runtime.Serialization.Formatters.Soap.SoapFormatter類的對象。從它們的名稱來看,我們不妨將它們分別稱為二進制格式器和XML格式器。

 

  本文將從這兩個格式器入手,先向大家介紹分別用它們如何實現序列化和反序列化,然后比較兩種格式器的不同點。接着我會向大家介紹實現序列化對對象類型的一些要求,同時還要向大家介紹兩種不同的序列化方式:基本序列化(Basic Serialization)和自定義序列化(Custom Serialization)。最后,我還會給大家介紹一個實例程序以加深大家對序列化機制的理解程度。

 

  一.二進制格式器(Binary Formatter) vs XML格式器(XML Formatter):

 

  下面我先向大家介紹兩種不同的格式器,分別用它們如何實現序列化機制和反序列化機制,請看下面的代碼:

 

 

#region Binary Serializers

public static System.IO.MemoryStream SerializeBinary(object request) {

 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = 

  new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

 System.IO.MemoryStream memStream = new System.IO.MemoryStream();

 serializer.Serialize(memStream, request);

 return memStream;

}

 

public static object DeSerializeBinary(System.IO.MemoryStream memStream) {

 memStream.Position=0;

 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializer = 

  new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

 object newobj = deserializer.Deserialize(memStream);

 memStream.Close();

 return newobj;

}

#endregion

 

#region XML Serializers

public static System.IO.MemoryStream SerializeSOAP(object request) {

 System.Runtime.Serialization.Formatters.Soap.SoapFormatter serializer = 

  new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();

 System.IO.MemoryStream memStream = new System.IO.MemoryStream();

 serializer.Serialize(memStream, request);

 return memStream;

}

 

public static object DeSerializeSOAP(System.IO.MemoryStream memStream) {

 object sr;

 System.Runtime.Serialization.Formatters.Soap.SoapFormatter deserializer = 

  new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();

 memStream.Position=0;

 sr = deserializer.Deserialize(memStream);

 memStream.Close();

 return sr;

}

#endregion

 

 

  從上面的代碼我們可以發現無論運用哪種格式器,其基本的過程都是一樣的,而且都是非常容易實現的,唯一的不同就是定義格式器的類型不同。不過在實際的應用中,二進制格式器往往應用於一般的桌面程序和網絡通訊程序中,而XML格式器稟承了XML技術的優點,大多數被應用於.Net Remoting和XML Web服務等領域。下面我們來分析一下兩種格式器各自的優點。

 

  二進制序列化的優點:

 

  1. 所有的類成員(包括只讀的)都可以被序列化;

 

  2. 性能非常好。

 

  XML序列化的優點:

 

  1. 互操作性好;

 

  2. 不需要嚴格的二進制依賴;

 

  3. 可讀性強。

 

  通過分析上面的代碼,我們知道了選擇二進制序列化的方式還是選擇XML序列化的方式僅僅是對不同的格式器進行選擇而已。你可以根據實際的需要選擇相應的格式器完成序列化和反序列化工作。同時請注意,代碼中的序列化函數和反序列化函數僅僅是在調用Serialize()和Deserialize()這兩個核心函數上產生了差別,即它們的參數不同。因此以上的代碼完成了一些最最基本但是很重要的功能,你可以將它們運用在你的程序中,或是將其進行適當擴充以滿足程序的特定需要。

 

 

  二.序列化機制對類的要求:

 

  如果你要對一個對象進行序列化,那么你必須將它的類型標記為[Serializable()],該操作是通過SerializableAttribute屬性來實現的。將SerializableAttribute屬性應用於一種數據類型可表明該數據類型的實例可以被序列化。如果正在序列化的對象圖中的任何類型未應用SerializableAttribute屬性,公共語言運行庫則會引發SerializationException。默認情況下,類型中由SerializableAttribute標記的所有公共和私有字段都會進行序列化,除非該類型實現ISerializable接口來重寫序列化進程(通過實現該接口我們便可以實現將在后面介紹的"自定義序列化")。默認的序列化進程會排除用NonSerializedAttribute屬性標記的字段,即你可以將該類型標記為[NonSerialized()]以表明它是不可以被序列化的。如果可序列化類型的字段包含指針、句柄或其他某些針對於特定環境的數據結構,並且不能在不同的環境中以有意義的方式重建,則最好將NonSerializedAttribute屬性應用於該字段。有關序列化的更多信息,請參閱System.Runtime.Serialization名字空間中的相關內容。

 

  下面我給大家介紹一個例子,以顯示如何正確的運用SerializableAttribute屬性和NonSerializedAttribute屬性。該程序中運用到了XML格式器,不過同時給出了二進制格式器為參考(程序中將其用"//"標注),其實現的結果是一樣的。該程序實現的功能是在序列化和反序列化操作前后測試對象因包含了[NonSerialized()]的字段而顯示不同的屏幕打印結果。其代碼如下:

 

 

using System;

using System.IO;

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Soap;

//using System.Runtime.Serialization.Formatters.Binary;

 

public class Test {

 public static void Main() {

  // 創建一個新的測試對象

  TestSimpleObject obj = new TestSimpleObject();

 

  Console.WriteLine("Before serialization the object contains: ");

  obj.Print();

 

  // 創建一個文件"data.xml"並將對象序列化后存儲在其中

  Stream stream = File.Open("data.xml", FileMode.Create);

  SoapFormatter formatter = new SoapFormatter();

  //BinaryFormatter formatter = new BinaryFormatter();

 

  formatter.Serialize(stream, obj);

  stream.Close();

  

  // 將對象置空

  obj = null;

 

  // 打開文件"data.xml"並進行反序列化得到對象

  stream = File.Open("data.xml", FileMode.Open);

  formatter = new SoapFormatter();

  //formatter = new BinaryFormatter();

 

  obj = (TestSimpleObject)formatter.Deserialize(stream);

  stream.Close();

 

  Console.WriteLine("");

  Console.WriteLine("After deserialization the object contains: ");

  obj.Print();

 }

}

 

// 一個要被序列化的測試對象的類

[Serializable()] 

 public class TestSimpleObject {

 public int member1;

 public string member2;

 public string member3;

 public double member4;

 

 // 標記該字段為不可被序列化的

[NonSerialized()] public string member5; 

 

public TestSimpleObject() {

 member1 = 11;

 member2 = "hello";

 member3 = "hello";

 member4 = 3.14159265;

 member5 = "hello world!";

}

 

public void Print() {

 Console.WriteLine("member1 = '{0}'", member1);

 Console.WriteLine("member2 = '{0}'", member2);

 Console.WriteLine("member3 = '{0}'", member3);

 Console.WriteLine("member4 = '{0}'", member4);

 Console.WriteLine("member5 = '{0}'", member5);

}

}

   三.基本序列化(Basic Serialization) vs 自定義序列化(Custom Serialization):

 

  .Net框架為我們提供了兩種方式的序列化:一種為基本序列化、另一種為自定義序列化。值得注意的是,序列化的方式和前面提到的序列化的格式是不同的概念。序列化的方式是指.Net框架將程序的數據轉化為能被存儲並傳輸的格式的實際過程,它是不管程序員運用了何種類型的格式器的(二進制格式器還是XML格式器)。而序列化的格式則指程序的數據是被轉化成二進制格式了還是被轉化成XML格式了。

 

  完成序列化的最簡單的方法便是讓.Net框架自動為我們完成整個過程,而我們不必去管它內部是如何具體實現的,這種方法便是前面提到的"基本序列化"。在這種方式下,我們需要做的僅僅是將類標記上[Serializable()]屬性。然后.Net框架便調用該類的對象並將它轉化為所需的格式。同時你還可以控制其中的某些字段不被序列化,方法就是前面所述的將該字段標記上[NonSerialized()]屬性。這樣,最最簡單和基本的序列化工作就完成了,不過其內部是如何實現的你是不得而知的,同時你也不能進一步控制序列化過程的程序行為。

 

  如果你要獲得對序列化的更大的控制權,那么你就得使用"自定義序列化"的方式。通過使用這種方式,你可以完全的控制類的哪些部分能被序列化而哪些部分不能,同時你還可以控制如何具體的進行序列化。運用該方式的好處就是能克服基本序列化所會遇到的問題。我們在運用基本序列化將一個類的對象序列化完畢並存儲在文件中后,假設該對象原來有三個字段,如果此時該對象增加了一個字段,那么再將該對象從文件中反序列化出來時會發生字段數不一致的錯誤。這樣的問題是基本序列化所不能解決的,只能運用自定義序列化的方式來解決。

 

  在介紹自定義序列化之前,我先給出介紹過程中所要用到的實例程序的代碼。這是一個時間安排程序,其中要用到將不同的時間格式進行轉化的操作。所以運用序列化的機制能很好的解決這個問題。

 

 

using System;

using System.Runtime.Serialization;

 

namespace SerializationSample {

[Serializable()]

 public class Schedule {

  protected System.DateTime start;

  protected System.DateTime end;

  // 每個時間間隔所要增加的毫秒數

  protected long interval;

 

  public System.DateTime Start {get{return start;}set{start=value;}}

  public System.DateTime End {get{return end;}set{end=value;}}

  public long Interval {get{return interval;}set{interval=value;}}

  public Schedule(System.DateTime Start, System.DateTime End, long Interval) {

   start=Start;

   end=End;

  interval=Interval;

}

 

// 如果已經到了結束的時間,則返回結束時間,否則返回下一次運行的時間

public System.DateTime NextRunTime {

 get {

  System.TimeSpan ts = new System.TimeSpan(end.Ticks-System.DateTime.Now.Ticks);

  if(ts.Milliseconds>0) {

   return System.DateTime.Now.AddMilliseconds(interval);

  } else {

   return end;

  }

 }

}

}

}

  自定義序列化:

 

  下面我就向大家介紹自定義序列化以及反序列化的具體過程。首先,程序的類必須實現System.Runtime.Serialization.ISerializable接口,該接口的功能就是允許對象控制其自己的序列化和反序列化過程。所以我們得重新定義上面的類:

 

 

[Serializable()]

public class ScheduleCustom : System.Runtime.Serialization.Iserializable 

 

  接下來,我們必須對該接口調用GetObjectData()的實現,也即我們必須在上面的類中給出GetObjectData()的具體實現。其函數原型如下:

 

 

void GetObjectData(SerializationInfo info, StreamingContext context); 

 

  上面的類中GetObjectData()的具體實現如下:

 

 

public void GetObjectData(SerializationInfo info,StreamingContext context) {

// 運用info對象來添加你所需要序列化的項

info.AddValue("start", start);

info.AddValue("end", end);

info.AddValue("interval", interval);

 

   然而對於這么一個簡單的方法,讀者可能不能理會到系列化帶來的強大功能,所以下面我就給這個方法添加一些東西。如果在系列化過程中我們要查看類型為DateTime的"start"屬性的輸出的話,其結果會是.Net框架默認的格式:

 

  2002-12-19T14:09:13.3457440-07:00

 

  而對於沒有.Net框架的用戶,或是在其他時間區域內的用戶而言,這么一個格式的時間可能是非常難以理解的,所以我們有必要將時間的格式轉化為格林威治標准時間格式,於是修改GetObjectData()方法如下:

 

 

public void GetObjectData(SerializationInfo info,StreamingContext context) {

// 運用info對象來添加你所需要序列化的項

// 同時,將"start"和"end"屬性的時間格式轉化為格林威治標准時間格式

info.AddValue("start", System.TimeZone.CurrentTimeZone.ToUniversalTime(start));

info.AddValue("end", System.TimeZone.CurrentTimeZone.ToUniversalTime(end));

info.AddValue("interval", interval);

info.AddValue("timeformat", "utc");

 

  這樣一來,我們在系列化過程中查看"start"屬性時就會得到如下結果:

 

   8/19/2002 9:09:13 PM

 

  同時請注意我們在GetObjectData()方法中添加的一個名為"timeformat"的額外屬性,通過它我們可以方便的知道系列化過程中所使用的時間格式。如果有興趣的話,你還可以從System.Globalization.DateTimeFormatInfo這個名字空間中獲取更多有關時間格式的信息。

 

  自定義反序列化:

 

  你可以通過調用一個自定義的構造函數來完成自定義反序列化的操作。該構造函數的定義如下:

 

 

public ScheduleCustom (SerializationInfo info,StreamingContext context); 

 

  在上面的類中,我們的ScheduleCustom()方法將完成把時間格式從格林威治標准時間格式反序列化為當地時間的格式的操作,其函數實現如下:

 

 

public ScheduleCustom (SerializationInfo info,StreamingContext context) {

 this.start = info.GetDateTime("start").ToLocalTime();

 this.end = info.GetDateTime("end").ToLocalTime();

 this.interval = info.GetInt32("interval");

 

  在完成自定義序列化和自定義反序列化后,我們的時間安排程序變成了如下形式:

 

 

using System;

using System.Runtime.Serialization;

 

namespace SerializationSample {

[Serializable()]

 public class ScheduleCustom : System.Runtime.Serialization.ISerializable {

 protected System.DateTime start;

 protected System.DateTime end;

 // 每個時間間隔所要增加的毫秒數

 protected long interval;

 

 public System.DateTime Start {get{return start;}set{start=value;}}

 public System.DateTime End {get{return end;}set{end=value;}}

 public long Interval {get{return interval;}set{interval=value;}}

 

 public ScheduleCustom(System.DateTime Start, System.DateTime End, long Interval) {

  start=Start;

  end=End;

  interval=Interval;

 }

 

// 如果已經到了結束的時間,則返回結束時間,否則返回下一次運行的時間

public System.DateTime NextRunTime {

 get {

  System.TimeSpan ts = new System.TimeSpan(end.Ticks-System.DateTime.Now.Ticks);

  if(ts.Milliseconds>0) {

   return System.DateTime.Now.AddMilliseconds(interval);

  } else {

   return end;

  }

 }

}

 

public void GetObjectData(SerializationInfo info,StreamingContext context) {

 // 運用info對象來添加你所需要序列化的項

 // 同時,將"start"和"end"屬性的時間格式轉化為格林威治標准時間格式

 info.AddValue("start", System.TimeZone.CurrentTimeZone.ToUniversalTime(start));

 info.AddValue("end", System.TimeZone.CurrentTimeZone.ToUniversalTime(end));

 info.AddValue("interval", interval);

 info.AddValue("timeformat", "utc");

}

 

public ScheduleCustom (SerializationInfo info,StreamingContext context) {

 this.start = info.GetDateTime("start").ToLocalTime();

 this.end = info.GetDateTime("end").ToLocalTime();

 this.interval = info.GetInt32("interval");

 }

}

}

 

 

  四.總結:

 

  本文向大家介紹了.Net框架下系列化機制的一些基本概念和基本的運用方法,讀者在讀完本文后,應該對以下幾個概念有個初步了解:二進制系列化、XML系列化、基本序列化和自定義系列化,並應能夠完成一些基本的系列化應用。最后,希望大家能合理有效的運用系列化機制並發揮它的功效以更好地滿足實際工作需要。

 

 

----------

    序列化又稱串行化,是.NET運行時環境用來支持用戶定義類型的流化的機制。其目的是以某種存儲形成使自定義對象持久化,或者將這種對象從一個地方傳輸到另一個地方。
    .NET框架提供了兩種串行化的方式:1、是使用BinaryFormatter進行串行化;2、使用SoapFormatter進行串行化;3、使用XmlSerializer進行串行化。第一種方式提供了一個簡單的二進制數據流以及某些附加的類型信息,而第二種將數據流格式化為XML存儲;第三種其實和第二種差不多也是XML的格式存儲,只不過比第二種的XML格式要簡化很多(去掉了SOAP特有的額外信息)。
    可以使用 [Serializable]屬性將類標志為可序列化的。如果某個類的元素不想被序列化,1、2可以使用 [NonSerialized]屬性來標志,2、可以使用[XmlIgnore]來標志。
     1、使用BinaryFormatter進行串行化
    下面是一個可串行化的類:
    
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using  System.IO;
using
 System.Runtime.Serialization.Formatters.Binary;
/// <summary>
/// ClassToSerialize 的摘要說明
/// </summary>
[Serializable]
public class ClassToSerialize
{
    public int id = 100;
    public string name = "Name";
    [NonSerialized]
    public string Sex = "男";
}

    下面是串行化和反串行化的方法:
    
public 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 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;
          Response.Write(c.name);
        Response.Write(c.Sex);
        fileStream.Close();
    }

    調用上述兩個方法就可以看到串行化的結果:Sex屬性因為被標志為[NonSerialized],故其值總是為null。
     2、使用SoapFormatter進行串行化
    和BinaryFormatter類似,我們只需要做一下簡單修改即可:
    a.將using語句中的.Formatter.Binary改為.Formatter.Soap;
    b.將所有的BinaryFormatter替換為SoapFormatter.
    c.確保報存文件的擴展名為.xml
    經過上面簡單改動,即可實現SoapFormatter的串行化,這時候產生的文件就是一個xml格式的文件。
     3、使用XmlSerializer進行串行化
    關於格式化器還有一個問題,假設我們需要XML,但是不想要SOAP特有的額外信息,那么我們應該怎么辦呢?有兩中方案:要么編寫一個實現IFormatter接口的類,采用的方式類似於SoapFormatter類,但是沒有你不需要的信息;要么使用庫類XmlSerializer,這個類不使用Serializable屬性,但是它提供了類似的功能。
    如果我們不想使用主流的串行化機制,而想使用XmlSeralizer進行串行化我們需要做一下修改:
    a.添加System.Xml.Serialization命名空間。
    b.Serializable和NoSerialized屬性將被忽略,而是使用XmlIgnore屬性,它的行為與NoSerialized類似。
    c.XmlSeralizer要求類有個默認的構造器,這個條件可能已經滿足了。
    下面看示例:
    要序列化的類:
    
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using  System.Xml.Serialization;
[Serializable]
public class Person
{
    private string name;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }


    public string Sex;
    public int Age = 31;
    public Course[] Courses;

    public Person()
    {
    }
    public Person(string Name)
    {
        name = Name;
        Sex = "男";
    }
}
[Serializable]
public class Course
{
    public string Name;
    [XmlIgnore]
    public string Description;
    public Course()
    {
    }
    public Course(string name, string description)
    {
        Name = name;
        Description = description;
    }
}  

    序列化和反序列化方法:
public void XMLSerialize()
     {
        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));
        Stream stream = new FileStream("c:\\cyj.XML",FileMode.Create,FileAccess.Write,FileShare.Read);
        xs.Serialize(stream,c);
        stream.Close();
    }
    public void XMLDeserialize()
    {
        XmlSerializer xs = new XmlSerializer(typeof(Person));
        Stream stream = new FileStream("C:\\cyj.XML",FileMode.Open,FileAccess.Read,FileShare.Read);
        Person p = xs.Deserialize(stream) as Person;
        Response.Write(p.Name);
        Response.Write(p.Age.ToString());
        Response.Write(p.Courses[0].Name);
        Response.Write(p.Courses[0].Description);
        Response.Write(p.Courses[1].Name);
        Response.Write(p.Courses[1].Description);
        stream.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">
  <Sex>男</Sex>
  <Age>31</Age>
  <Courses>
    <Course>
      <Name>英語</Name>
      <Description>交流工具</Description>
    </Course>
    <Course>
      <Name>數學</Name>
      <Description>自然科學</Description>
    </Course>
  </Courses>
  <Name>cyj</Name>
</Person>

     4、自定義序列化
    如果你希望讓用戶對類進行串行化,但是對數據流的組織方式不完全滿意,那么可以通過在自定義類中實現接口來自定義串行化行為。這個接口只有一個方法,GetObjectData. 這個方法用於將對類對象進行串行化所需要的數據填進SerializationInfo對象。你使用的格式化器將構造SerializationInfo對象,然后在串行化時調用GetObjectData. 如果類的父類也實現了ISerializable,那么應該調用GetObjectData的父類實現。
    如果你實現了ISerializable,那么還必須提供一個具有特定原型的構造器,這個構造器的參數列表必須與GetObjectData相同。這個構造器應該被聲明為私有的或受保護的,以防止粗心的開發人員直接使用它。
    示例如下:
    實現ISerializable的類:
    
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
/// <summary>
/// Employee 的摘要說明
/// </summary>
[Serializable]
public class Employee:ISerializable
{
    public int EmpId=100;
    public string EmpName="劉德華";
    [NonSerialized]
    public string NoSerialString = "NoSerialString-Test";
    public Employee()
    {
        //
        // TODO: 在此處添加構造函數邏輯
        //
    }
    private Employee(SerializationInfo info, StreamingContext ctxt)
    {
        EmpId = (int)info.GetValue("EmployeeId", typeof(int));
        EmpName = (String)info.GetValue("EmployeeName",typeof(string));
        //NoSerialString = (String)info.GetValue("EmployeeString",typeof(string));
    }
    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        info.AddValue("EmployeeId", EmpId);
        info.AddValue("EmployeeName", EmpName);
        //info.AddValue("EmployeeString", NoSerialString);
    }
}

    序列化和反序列化方法:
public void OtherEmployeeClassTest()
     {
        Employee mp = new Employee();
        mp.EmpId = 10;
        mp.EmpName = "邱楓";
        mp.NoSerialString = "你好呀";
        Stream steam = File.Open("c:\\temp3.dat", FileMode.Create);
        BinaryFormatter bf = new BinaryFormatter();
        Response.Write("Writing Employee Info:");
        bf.Serialize(steam,mp);
        steam.Close();
        mp = null;
        //反序列化
        Stream steam2 = File.Open("c:\\temp3.dat", FileMode.Open);
        BinaryFormatter bf2 = new BinaryFormatter();
        Response.Write("Reading Employee Info:");
        Employee mp2 = (Employee)bf2.Deserialize(steam2);
        steam2.Close();
        Response.Write(mp2.EmpId);
        Response.Write(mp2.EmpName);
        Response.Write(mp2.NoSerialString);
    }

PS:本文章屬個人學習總結,部分內容參考互聯網上的相關文章。 其中如果發現個人總結有不正確的認知或遺漏的地方請評論告知,歡迎交流。

-----------------

序列化是將一個對象轉換成字節流以達到將其長期保存在內存、數據庫或文件中的處理過程。它的主要目的是保存對象的狀態以便以后需要的時候使用。與其相反的過程叫做反序列化。 

序列化一個對象 

為了序列化一個對象,我們需要一個被序列化的對象,一個容納被序列化了的對象的(字節)流和一個格式化器。進行序列化之前我們先看看System.Runtime.Serialization名字空間。ISerializable接口允許我們使任何類成為可序列化的類。 

如果我們給自己寫的類標識[Serializable]特性,我們就能將這些類序列化。除非類的成員標記了[NonSerializable],序列化會將類中的所有成員都序列化。 

序列化的類型

  • 二進制(流)序列化
  • SOAP序列化
  • XML序列化
晴風曉月
晴風曉月
翻譯於 4年前
2人頂
 翻譯得不錯哦!
 

二進制(流)序列化:

二進制(流)序列化是一種將數據寫到輸出流,以使它能夠用來自動重構成相應對象的機制。二進制,其名字就暗示它的必要信息是保存在存儲介質上,而這些必要信息要求創建一個對象的精確的二進制副本。在二進制(流)序列化中,整個對象的狀態都被保存起來,而XML序列化只有部分數據被保存起來。為了使用序列化,我們需要引入System.Runtime.Serialization.Formatters.Binary名字空間. 下面的代碼使用BinaryFormatter類序列化.NET中的string類型的對象。 

using System;
using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace SerializationTest { class Program { static void Main(string[] args) { //Serialization of String Object string strobj = "test string for serialization"; FileStream stream = new FileStream("C:\\StrObj.txt", FileMode.Create, FileAccess.Write , FileShare.None); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, strobj); stream.Close(); //Deserialization of String Object FileStream readstream = new FileStream("C:\\StrObj.txt", FileMode.Open , FileAccess.Read , FileShare.Read ); string readdata = (string)formatter.Deserialize(readstream); readstream.Close(); Console.WriteLine(readdata); Console.ReadLine(); } } }
晴風曉月
晴風曉月
翻譯於 4年前
1人頂
 翻譯得不錯哦!
 

SOAP序列化:

SOAP協議是一個在異構的應用程序之間進行信息交互的理想的選擇。我們需要在應用程序中添加System.Runtime.Serialization.Formatters.Soap名字空間以便在.Net中使用SOAP序列化。SOAP序列化的主要優勢在於可移植性。SoapFormatter把對象序列化成SOAP消息或解析SOAP消息並重構被序列化的對象。下面的代碼在.Net中使用SoapFormatter類序列化string類的對象。 

using System; 
using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Soap ; namespace SerializationTest { class Program { static void Main(string[] args) { //Serialization of String Object string strobj = "test string for serialization"; FileStream stream = new FileStream("C:\\StrObj.txt", FileMode.Create, FileAccess.Write , FileShare.None); SoapFormatter formatter = new SoapFormatter(); formatter.Serialize(stream, strobj); stream.Close(); //Deserialization of String Object FileStream readstream = new FileStream("C:\\StrObj.txt", FileMode.Open , FileAccess.Read , FileShare.Read ); string readdata = (string)formatter.Deserialize(readstream); readstream.Close(); Console.WriteLine(readdata); Console.ReadLine(); } } }
晴風曉月
晴風曉月
翻譯於 4年前
1人頂
 翻譯得不錯哦!
 

XML序列化:

根據MSDN的描述,“XML序列化將一個對象或參數的公開字段和屬性以及方法的返回值轉換(序列化)成遵循XSD文檔標准的XML流。因為XML是一個開放的標准,XML能被任何需要的程序處理,而不管在什么平台下,因此XML序列化被用到帶有公開的屬性和字段的強類型類中,它的這些發生和字段被轉換成序列化的格式(在這里是XML)存儲或傳輸。” 

我們必須添加System.XML.Serialization引用以使用XML序列化。使用XML序列化的基礎是XmlSerializer。下面的代碼是在.Net中使用XmlSerializer類序列化string對象。 

using System;
using System.IO; using System.Xml.Serialization; namespace SerializationTest { class Program { static void Main(string[] args) { //Serialization of String Object string strobj = "test string for serialization"; FileStream stream = new FileStream("C:\\StrObj.txt", FileMode.Create, FileAccess.Write , FileShare.None); XmlSerializer xmlserializer = new XmlSerializer(typeof(string)); xmlserializer.Serialize(stream, strobj); stream.Close(); //Deserialization of String Object FileStream readstream = new FileStream("C:\\StrObj.txt", FileMode.Open , FileAccess.Read , FileShare.Read ); string readdata = (string)xmlserializer.Deserialize(readstream); readstream.Close(); Console.WriteLine(readdata); Console.ReadLine(); } } }
晴風曉月
晴風曉月
翻譯於 4年前
1人頂
 翻譯得不錯哦!
 

什么是格式化器?

一個格式化器用來確定一個對象的序列格式。它們目的是在網絡上傳輸一個對象之前將其序列化成合適的格式。它們提供IFormatter接口。在.NET里提供了兩個格式化類:BinaryFormatter和SoapFormatter,它們都繼承了IFormatter接口。 

使用序列化

序列化允許開發人員保存一個對象的狀態並在需要的時候重構對象,同時很好地支持對象存儲和數據交換。通過序列化,開發人員可以利用Web Service發送對象到遠端應用程序,從一個域傳輸對象到另一個域,以XML的格式傳輸一個對象並能通過防火牆,或者在應用程序間保持安全性或用戶特定信息等等

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM