国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

C# - 序列化和反序列化

2019-11-17 04:09:29
字體:
來源:轉載
供稿:網友
一、序列化的概念

序列化就是把一個對象保存到一個文件或數據庫字段中去,反序列化就是在適當的時候把這個文件再轉化成原來的對象使用。

      需要分清楚的概念:對象的序列化而不是類的序列化。對象的序列化表明C#提供了將運行中的對象(實時數據)寫入到硬盤文件或者數據庫中,此功能可以運用在需要保留程序運行時狀態信息的環境下。

      使用序列化有兩個最重要的原因:

一個原因是將對象的狀態永久保存在存儲媒體中,以便可以在以后重新創建精確的副本;

另一個原因是通過值將對象從一個應用程序域發送到另一個應用程序域中。

      前提:要將對象的類聲明為可以序列化。



最主要的作用有:

1、在進程下次啟動時讀取上次保存的對象的信息  

2、在不同的AppDomain或進程之間傳遞數據  

3、在分布式應用系統中傳遞數據

......



二、永久存儲

通常需要將一個對象的各字段的值存儲到磁盤中,這樣以后可以檢索這些數據。盡管不依賴序列化也可以很容易地做到這一點,但這樣的方法通常十分麻煩并且容易出錯,在您需要跟蹤對象的層次結構時將變得越來越復雜。設想一下編寫包含數以千計對象的大型商業應用程序,將不得不為每一對象編寫代碼以將字段和屬性保存到磁盤上和從磁盤上還原它們,這是多么的復雜。而序列化為實現上述目標提供了一個方便的機制。

公共語言運行庫管理對象在內存中的存儲方式并通過使用反射提供自動的序列化機制。當序列化一個對象時,類的名稱、程序集和類實例的所有數據成員都被寫入存儲中。對象通常在成員變量中存儲對其他實例的引用。在序列化類時,序列化引擎跟蹤已被序列化的引用對象,以確保同一對象不會被多次序列化。隨 一起提供的序列化結構自動正確處理對象圖和循環引用。對于對象圖的唯一要求就是,由被序列化的對象引用的所有對象還必須標記為 Serializable。如果沒有進行此標記,當序列化程序嘗試序列化未標記的對象時,將引發一個異常。

當反序列化已序列化的類時,重新創建該類并且自動還原所有數據成員的值。



三、值封送

      對象只在創建它們的應用程序域中有效。將對象作為一個參數傳遞或將其作為結果返回的任何嘗試都將失敗,除非該對象派生自 MarshalByRefObject 或被標記為 Serializable。如果該對象被標記為 Serializable,該對象將被自動序列化,從一個應用程序域傳輸到其他的應用程序域,然后被反序列化以在第二個應用程序域中生成該對象的精確副本。此過程通常被稱作值封送。

當對象從 MarshalByRefObject 派生時,從一個應用程序域將對象引用傳遞到另一個應用程序域,而不是傳遞該對象本身。還可將從 MarshalByRefObject 派生的對象標記為 Serializable。當該對象與遠程處理一起使用時,負責序列化的格式化程序(該格式化程序已由代理選擇器 SurrogateSelector 預先配置)控制序列化過程,并用代理代替從 MarshalByRefObject 派生的所有對象。如果沒有適當的 SurrogateSelector,則序列化結構遵循在序列化過程的步驟中描述的標準序列化規則。



四、基本序列化

      使一個類可序列化的最簡單方式是按如下所示使用 Serializable 屬性標記。

[Serializable]

public class MyObject {

  public int n1 = 0;

  public int n2 = 0;

  public String str = null;

}

以下代碼示例說明該類的實例是如何被序列化到一個文件中的。

MyObject obj = new MyObject();

obj.n1 = 1;

obj.n2 = 24;

obj.str = "Some String";

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Create, Fileaccess.Write, FileShare.None);

formatter.Serialize(stream, obj);

stream.Close();

該示例使用二進制格式化程序執行序列化。您需要做的所有工作就是創建流的實例和您想要使用的格式化程序,然后對該格式化程序調用 Serialize 方法。要序列化的流和對象作為參數提供給該調用。盡管在此示例中并沒有顯式闡釋這一點,但一個類的所有成員變量都將被序列化,即使是那些已標記為私有的變量。在此方面,二進制序列化不同于 xmlSerializer 類,后者只序列化公共字段。

將對象還原回其以前的狀態十分簡單。首先,創建用于讀取的流和格式化程序,然后指示格式化程序反序列化該對象。下面的代碼示例說明如何執行上述的操作。

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);

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

stream.Close();



// Here's the PRoof.

Console.WriteLine("n1: {0}", obj.n1);

Console.WriteLine("n2: {0}", obj.n2);

Console.WriteLine("str: {0}", obj.str);

上面所用的 BinaryFormatter 非常有效,生成了非常簡潔的字節流。通過該格式化程序序列化的所有對象也可以通過該格式化程序進行反序列化,這使該工具對于序列化將在 .NET Framework 上被反序列化的對象而言十分理想。需要特別注意的是,在反序列化一個對象時不調用構造函數。出于性能方面的原因對反序列化施加了該約束。但是,這違反了運行庫與對象編寫器之間的一些通常約定,開發人員應確保他們在將對象標記為可序列化時了解其后果。

如果可移植性是必需的,則轉為使用 SoapFormatter。只需用 SoapFormatter 代替上面代碼中的 BinaryFormatter,并且如前面一樣調用 Serialize 和 Deserialize。此格式化程序為上面使用的示例生成以下輸出。



<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/"

  SOAP-ENV:encodingStyle=

  "http://schemas.microsoft.com/soap/encoding/clr/1.0"

  "http://schemas.xmlsoap.org/soap/encoding/"

  xmlns:a1="http://schemas.microsoft.com/clr/assem/ToFile">



  <SOAP-ENV:Body>

    <a1:MyObject id="ref-1">

      <n1>1</n1>

      <n2>24</n2>

      <str id="ref-3">Some String</str>

    </a1:MyObject>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

需要特別注意的是,Serializable 屬性不能被繼承。如果我們從 MyObject 派生一個新類,此新類必須也用該屬性標記,否則將無法被序列化。例如,當試圖序列化下面的類的實例時,您將獲得 SerializationException,通知您 MyStuff 類型沒有標記為可序列化。

public class MyStuff : MyObject

{

  public int n3;

}

使用 Serializable 屬性十分方便,但它具有上面所述的限制。在對類進行編譯后,就不能再向該類添加序列化。

五、序列化舉例

在C#中常見的序列化的方法主要也有三個:

BinaryFormatter

SoapFormatter

XML序列化

本文就通過一個小例子主要說說這三種方法的具體使用和異同點:

這個例子就是使用三種不同的方式把一個Book對象進行序列化和反序列化,當然這個Book類首先是可以被序列化的。



Book類

using System;

using System.Collections;

using System.Text;



namespace SerializableTest

{

    [Serializable]

    public class Book

    {

        public Book()

        {

            alBookReader = new ArrayList();

        }



        public string strBookName;



        [NonSerialized]

        public string strBookPwd;



        private string _bookID;

        public string BookID

        {

            get { return _bookID; }

            set { _bookID = value; }

        }



        public ArrayList alBookReader;



        private string _bookPrice;

        public void SetBookPrice(string price)

        {

            _bookPrice = price;

        }



        public void Write()

        {

            Console.WriteLine(/"Book ID:/" + BookID);

            Console.WriteLine(/"Book Name:/" + strBookName);

            Console.WriteLine(/"Book PassWord:/" + strBookPwd);

            Console.WriteLine(/"Book Price:/" + _bookPrice);

            Console.WriteLine(/"Book Reader:/");

            for (int i = 0; i < alBookReader.Count; i++)

            {

                Console.WriteLine(alBookReader[i]); [Page]

            }

        }

    }

}

這個類比較簡單,就是定義了一些public字段和一個可讀寫的屬性,一個private字段,一個標記為[NonSerialized]的字段,具體會在下面的例子中體現出來



1、BinaryFormatter序列化方式

序列化,就是給Book類賦值,然后進行序列化到一個文件中

         Book book = new Book();

            book.BookID = /"1/";

            book.alBookReader.Add(/"gspring/");

            book.alBookReader.Add(/"永春/");

            book.strBookName = /"C#強化/";

            book.strBookPwd = /"*****/";

            book.SetBookPrice(/"50.00/");

            BinarySerialize serialize = new BinarySerialize();

            serialize.Serialize(book);  //2、反序列化



            BinarySerialize serialize = new BinarySerialize();

            Book book = serialize.DeSerialize();

            book.Write();   //3、測試用的



BinarySerialize類

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Runtime.Serialization.Formatters.Binary;



namespace SerializableTest

{

    public class BinarySerialize

    {

        string strFile = /"c:////book.data/";



        public void Serialize(Book book)

        {

            using (FileStream fs = new FileStream(strFile, FileMode.Create))

            {

                BinaryFormatter formatter = new BinaryFormatter();

                formatter.Serialize(fs, book);

            }

        }



        public Book DeSerialize()

        {

            Book book;

            using (FileStream fs = new FileStream(strFile, FileMode.Open))

            {

                BinaryFormatter formatter = new BinaryFormatter(); [Page]

                book = (Book)formatter.Deserialize(fs);

            }

            return book;

        }

    }

}

主要就是調用System.Runtime.Serialization.Formatters.Binary空間下的BinaryFormatter類進行序列化和反序列化,以縮略型二進制格式寫到一個文件中去,速度比較快,而且寫入后的文件已二進制保存有一定的保密效果。

調用反序列化后的截圖如下:



也就是說除了標記為NonSerialized的其他所有成員都能序列化



2、SoapFormatter序列化方式

調用序列化和反序列化的方法和上面比較類似,我就不列出來了,主要就看看SoapSerialize類

SoapSerialize類

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Runtime.Serialization.Formatters.Soap;



namespace SerializableTest

{

    public class SoapSerialize

    {

        string strFile = /"c:////book.soap/";



        public void Serialize(Book book)

        {

            using (FileStream fs = new FileStream(strFile, FileMode.Create))

            {

                SoapFormatter formatter = new SoapFormatter();

                formatter.Serialize(fs, book);

            }

        }



        public Book DeSerialize()

        {

            Book book;

            using (FileStream fs = new FileStream(strFile, FileMode.Open))

            {

                SoapFormatter formatter = new SoapFormatter();

                book = (Book)formatter.Deserialize(fs);



           }

            return book;

        }

    }

}

主要就是調用System.Runtime.Serialization.Formatters.Soap空間下的SoapFormatter類進行序列化和反序列化,使用之前需要應用System.Runtime.Serialization.Formatters.Soap.dll(.net自帶的)

序列化之后的文件是Soap格式的文件(簡單對象訪問協議(Simple Object Access Protocol,SOAP),是一種輕量的、簡單的、基于XML的協議,它被設計成在WEB上交換結構化的和固化的信息。 SOAP 可以和現存的許多因特網協議和格式結合使用,包括超文本傳輸協議(HTTP),簡單郵件傳輸協議(SMTP),多用途網際郵件擴充協議(MIME)。它還支持從消息系統到遠程過程調用(RPC)等大量的應用程序。SOAP使用基于XML的數據結構和超文本傳輸協議(HTTP)的組合定義了一個標準的方法來使用Internet上各種不同操作環境中的分布式對象。)

調用反序列化之后的結果和方法一相同



3、XML序列化方式

調用序列化和反序列化的方法和上面比較類似,主要就看看XmlSerialize類

XmlSerialize類

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Xml.Serialization;



namespace SerializableTest

{

    public class XmlSerialize

    {

        string strFile = /"c:////book.xml/";



        public void Serialize(Book book)

        {

            using (FileStream fs = new FileStream(strFile, FileMode.Create))

            {

                XmlSerializer formatter = new XmlSerializer(typeof(Book));

                formatter.Serialize(fs, book);

            }

        }



        public Book DeSerialize()

        {

            Book book;

            using (FileStream fs = new FileStream(strFile, FileMode.Open))

            {

                XmlSerializer formatter = new XmlSerializer(typeof(Book));

                book = (Book)formatter.Deserialize(fs);

            }

            return book;

        }

    }

}

從這三個測試類我們可以看出來其實三種方法的調用方式都差不多,只是具體使用的類不同

xml序列化之后的文件就是一般的一個xml文件:

book.xml

<?xml version=/"1.0/"?>

<Book xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/" xmlns:xsd=/"http://www.w3.org/2001/XMLSchema/">

  <strBookName>C#強化</strBookName>

  <strBookPwd>*****</strBookPwd>

  <alBookReader>

    <anyType xsi:type=/"xsd:string/">gspring</anyType>

    <anyType xsi:type=/"xsd:string/">永春</anyType>

  </alBookReader>

  <BookID>1</BookID>

</Book>

輸出截圖如下:



也就是說采用xml序列化的方式只能保存public的字段和可讀寫的屬性,對于private等類型的字段不能進行序列化



關于循環引用:

比如在上面的例子Book類中加入如下一個屬性:

        public Book relationBook;

在調用序列化時使用如下方法:

            Book book = new Book();

            book.BookID = /"1/"; [Page]

            book.alBookReader.Add(/"gspring/");

            book.alBookReader.Add(/"永春/");

            book.strBookName = /"C#強化/";

            book.strBookPwd = /"*****/";



            book.SetBookPrice(/"50.00/");



            Book book2 = new Book();

            book2.BookID = /"2/";

            book2.alBookReader.Add(/"gspring/");

            book2.alBookReader.Add(/"永春/");

            book2.strBookName = /".NET強化/";

            book2.strBookPwd = /"*****/";

            book2.SetBookPrice(/"40.00/");



            book.relationBook = book2;

            book2.relationBook = book;

            BinarySerialize serialize = new BinarySerialize();

            serialize.Serialize(book);

這樣就會出現循環引用的情況,對于BinarySerialize和SoapSerialize可以正常序列化(.NET內部進行處理了),對于XmlSerialize出現這種情況會報錯:/"序列化類型 SerializableTest.Book 的對象時檢測到循環引用。/"







、使用對象序列化,再反序列化回來就實現了內存的copy,實現對象的復制功能

/// <summary>

/// 把對象序列化并返回相應的字節

/// </summary>

/// <param name="pObj">需要序列化的對象</param>

/// <returns>byte[]</returns>

public  byte[] SerializeObject(object pObj)

{

       if(pObj == null)

              return null;

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

       BinaryFormatter formatter = new BinaryFormatter();

       formatter.Serialize(_memory,pObj);

       _memory.Position = 0;

       byte[] read = new byte[_memory.Length];

       _memory.Read(read,0,read.Length);

       _memory.Close();

       return read;

}



/// <summary>

/// 把字節反序列化成相應的對象

/// </summary>

/// <param name="pBytes">字節流</param>

/// <returns>object</returns>

public  object DeserializeObject(byte[] pBytes)

{

       object _newOjb = null;

       if(pBytes == null)

              return _newOjb;

       System.IO.MemoryStream _memory = new System.IO.MemoryStream(pBytes);

       _memory.Position = 0;

       BinaryFormatter formatter = new BinaryFormatter();

       _newOjb = formatter.Deserialize(_memory);

       _memory.Close();

       return _newOjb;

}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 万全县| 白城市| 朝阳区| 永善县| 正蓝旗| 茶陵县| 梅州市| 得荣县| 财经| 合阳县| 勃利县| 彭泽县| 锦州市| 泾阳县| 钦州市| 包头市| 柳州市| 伊金霍洛旗| 鄂伦春自治旗| 廊坊市| 麻城市| 收藏| 辉南县| 徐州市| 仁化县| 遵义市| 平利县| 砚山县| 正宁县| 香港 | 墨竹工卡县| 资阳市| 舟曲县| 班戈县| 洛川县| 聊城市| 平遥县| 荔波县| 汕尾市| 杂多县| 望江县|