C# 序列化理解 2(轉)

來源:互聯網
上載者:User

標籤:

一、概述

序列化是把對象轉變成流。相反的過程就是還原序列化。

哪些場合用到這項技術呢?

1. 把對象儲存到本地,下次運行程式時恢複這個對象。

2. 把對象傳送到網路的另一台終端上,然後在此終端還原這個對象。

3. 複製系統的粘帖板中,然後用快速鍵Ctrl+V恢複這個對象。

常用的序列化流有Binary(二進位流),XML,SOAP。

二、序列化和還原序列化使用案例:

這裡我們把序列化和還原序列化以功能類的形式展現:

 

 public class Serializer    {        //將類型序列化為字串        public static string Serialize<T>(T t) where T : class        {             using(MemoryStream stream=new MemoryStream())            {                BinaryFormatter formatter = new BinaryFormatter();                formatter.Serialize(stream, t);                return System.Text.Encoding.UTF8.GetString(stream.ToArray());            }        }        //將類型序列化為檔案        public static void SerializeToFile<T>(T t, string path, string fullName) where T : class        {            if (!Directory.Exists(path))            {                Directory.CreateDirectory(path);            }            string fullPath = string.Format(@"{0}\{1}", path, fullName);            using (FileStream stream = new FileStream(fullPath,FileMode.OpenOrCreate))            {                BinaryFormatter formatter = new BinaryFormatter();                formatter.Serialize(stream, t);                stream.Flush();            }        }        //將類型序列化為檔案        public static void SerializeToFileByXml<T>(T t, string path, string fullName) where T : class        {            if (!Directory.Exists(path))            {                Directory.CreateDirectory(path);            }                        string fullPath = string.Format(@"{0}\{1}", path, fullName);            using (FileStream stream = new FileStream(fullPath, FileMode.OpenOrCreate))            {                XmlSerializer formatter = new XmlSerializer(typeof(T));                formatter.Serialize(stream, t);                stream.Flush();            }        }        //將字串還原序列化為類型        public static TResult Deserialize<TResult>(string s) where TResult : class        {            byte[] bs = System.Text.Encoding.UTF8.GetBytes(s);            using (MemoryStream stream = new MemoryStream(bs))            {                BinaryFormatter formatter = new BinaryFormatter();                return formatter.Deserialize(stream) as TResult;            }        }        //將檔案還原序列化為類型        public static TResult DeserializeFromFile<TResult>(string path) where TResult : class        {            using (FileStream stream = new FileStream(path,FileMode.Open))            {                BinaryFormatter formatter = new BinaryFormatter();                return formatter.Deserialize(stream) as TResult;            }        }        //將xml檔案還原序列化為類型        public static TResult DeserializeFromFileByXml<TResult>(string path) where TResult : class        {            using (FileStream stream = new FileStream(path, FileMode.Open))            {                XmlSerializer formatter = new XmlSerializer(typeof(TResult)); ;                return formatter.Deserialize(stream) as TResult;            }        }    }

上面案例中的方法是以泛型方法實現的,其中附加了泛型約束,保證泛型安全。

序列化功能類有了下面我們建一個Book對象,用它來測試我們的功能類。

    [Serializable]    public class Book    {        [NonSerialized]        private string _bookPwd;        [field: NonSerialized]        public event EventHandler NameChanged;        private string _bookName;        private string _bookID;        public ArrayList alBookReader;        public string _bookPrice;        public Book()        {            alBookReader = new ArrayList();        }        public string BookName        {            get { return _bookName; }            set            {                if (NameChanged != null)                {                    NameChanged(this, null);                }                _bookName = value;            }        }        public void BookPwd(string pwd)        {             _bookPwd=pwd;        }               public string BookID        {            get { return _bookID; }            set { _bookID = value; }        }        public void SetBookPrice(string price)        {            _bookPrice = price;        }        [OnDeserializedAttribute]        public void changeName(StreamingContext context)        {            this.BookName = "C#深入淺出";        }        public void Write()        {            Console.WriteLine("Book ID:" + BookID);            Console.WriteLine("Book Name:" + BookName);            Console.WriteLine("Book Password:" + _bookPwd);            Console.WriteLine("Book Price:" + _bookPrice);            Console.WriteLine("Book Reader:");            for (int i = 0; i < alBookReader.Count; i++)            {                Console.WriteLine(alBookReader[i]);            }        }    }

 

關鍵介紹:
1.[Serializable]特性定義該類型可以被序列化;

2.[NonSerialized]定義某個屬性不被序列化,即:內部成員被NonSerialized禁止序列化特性標記;

3.[field: NonSerialized]定義事件不被序列化;

4.[OnDeserializedAttribute]當它應用於某個方法時,會指定對象被還原序列化後立即執行此方法。

5.[OnDeserializingAttribute]當它應用於某個方法時,會指定對象被還原序列化時立即執行此方法。

6.[OnSerializedAttribute]如果將對象圖應用於某個方法時,會指定在序列化該對象圖後是否調用此方法。

7.[OnSerializingAttribute]當它應用於某個方法時,會指定在對象序列化前調用此方法。、

我們用控制台程式實現序列化和還原序列化:

static void Main(string[] args)        {            string path = "c:\\Test\\";            Book book = new Book();            book.NameChanged += new EventHandler(make_NameChanged);            book.BookID = "2001";            book.alBookReader.Add("Abel");            book.alBookReader.Add("Tomson");            book.BookName = "敏捷無敵";            book.BookPwd("*****");            book.SetBookPrice("102.00");            //對象序列化            Serializer.SerializeToFileByXml<Book>(book, path, "book.txt");            //對象還原序列化            Book anothorbookserialize = new Book();            anothorbookserialize = Serializer.DeserializeFromFileByXml<Book>(path + "book.txt");            anothorbookserialize.Write();            Console.ReadKey();        }        static void make_NameChanged(object sender, EventArgs e)        {            Console.WriteLine("Name Changed");        }

我們的案例是調用XML序列化流檔案形式,序列化執行後的檔案如下:

<?xml version="1.0"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <alBookReader>
    <anyType xsi:type="xsd:string">Abel</anyType>
    <anyType xsi:type="xsd:string">Tomson</anyType>
  </alBookReader>
  <_bookPrice>102.00</_bookPrice>
  <BookName>敏捷無敵</BookName>
  <BookID>2001</BookID>
</Book>

還原序列化輸出如下:

Name Changed
Book ID:2001
Book Name:敏捷無敵
Book Password:
Book Price:102.00
Book Reader:
Abel
Tomson

結果分析:

[NonSerialized]Book Password屬性在序列化XML檔案中沒有出現Book Password。

[field: NonSerialized]NameChanged事件,在序列化XML檔案中沒有出現NameChanged。

[OnDeserializedAttribute]changeName()方法,執行還原序列化後沒有立即執行changeName()方法,Book Name名稱沒有改變,需要通過Binary流形式才能成功執行方法。

    //序列化    Serializer.SerializeToFile<Book>(book, path, "book.txt");    //還原序列化    anothorbookserialize = Serializer.DeserializeFromFile<Book>(path + "book.txt");

我們以XML流為例是為了更好的理解序列化和還原序列化的執行過程,實際應用中多數以Binary流形式實現序列化和還原序列化較多。

三、繼承ISerializable介面更靈活的控制序列化過程:

  當以上Serializable特性無法滿足複雜的序列化過程時就需要實現ISerializable介面了。

  以下是格式化器的工作流程:如果格式化器在序列化一個對象的時候,發現對象實現了ISerializable介面,那他會忽略類所有序列化特性,轉而調用GetObjectData方法的一個SerializationInfo對象,方法內部負責該對象屬性的添加。還原序列化時調用該對象受保護帶參數構造方法中的一個SerializationInfo對象,方法內部對象屬性賦值。

下面我們實現ISerializable介面的子類型應負責父類型的序列化為例:

1.父類同樣實現了ISerializable介面

 

[Serializable]    public class Person:ISerializable    {        public string Name{get;set;}                public Person()        {        }        protected Person(SerializationInfo info,StreamingContext context)        {            Name = info.GetString("Name");        }        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)        {            info.AddValue("Name",Name);        }    }    [Serializable]    public class Employee: Person , ISerializable    {        public int Salary{get;set;}
public Employee() { } protected Employee(SerializationInfo info, StreamingContext context) { Salary = info.GetInt32("Salary"); Name = info.GetString("Name"); } public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info,context); info.AddValue("Salary", Salary); } }

注意:Employee中的GetObjectData方法覆蓋了基類Person中的虛方法GetObjectData。

 

Employee employee = new Employee() { Name = "Abel", Salary=1220 };BinarySerializer.SerializeToFile<Employee>(employee, strFile, "employee.txt");employee = BinarySerializer.DeserializeFromFile<Employee>("c:\\Test\\employee.txt");Console.WriteLine(employee.Name);Console.WriteLine(employee.Salary);

2.若父類沒有實現了ISerializable介面如何處理呢?

我們要實現繼承ISerializable介面的Employee類的一個父類Person,Person沒有實現ISerializable介面,序列化器沒有預設去處理Person對象,只能由我們自己去做。

下面我們用具體執行個體實現:

   [Serializable]    public class Person    {        public string Name{get;set;} }    [Serializable]    public class Employee: Person , ISerializable    {        public int Salary{get;set;}        public Employee()        {        }        protected Employee(SerializationInfo info, StreamingContext context)        {            Salary = info.GetInt32("Salary");            Name = info.GetString("Name");        }        public void GetObjectData(SerializationInfo info, StreamingContext context)        {            info.AddValue("Name", Name);            info.AddValue("Salary", Salary);        }    }

 

在這此序列化學習中我們用到了事件、泛型和流檔案的處理知識,通過序列化我們可以實現本地載入,遠程還原對象。

得到了一個Serializer工具類,該工具類封裝了序列化和還原序列化的過程。

 

C# 序列化理解 2(轉)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.