C#: .net序列化及反序列化 [XmlElement(“節點名稱”)] [XmlAttribute(“節點屬性”)] (上篇)


.net序列化及反序列化

序列化是指一個對象的實例可以被保存,保存成一個二進制串,當然,一旦被保存成二進制串,那么也可以保存成文本串了。
比如,一個計數器,數值為2,我們可以用字符串“2”表示。
如果有個對象,叫做connter,當前值為2,那么可以序列化成“2”,反向的,也可以從“2”得到值為2的計數器實例。
這樣,關機時序列化它,開機時反序列化它,每次開機都是延續的。不會都是從頭開始。

列化概念的提出和實現,可以使我們的應用程序的設置信息保存和讀取更加方便

序列化有很多好處,比如,在一台機器上產生一個實例,初始化完畢,然后可以序列化,通過網絡傳送到另一台機器,然后反序列化,得到對象實例,之后再執行某些業務邏輯,得到結果,再序列化,返回第一台機器,第一台機器得到對象實例,得到結果。
這個例子是目前比較先進的“智能代理”的原理。

當前比較熱火的web services使用soap協議,soap協議也是以對象的可序列化為基礎的。

一 概述
.NET Framework為處理XML數據提供了許多不同的類庫。XmlDocument類能讓你像處理文件一樣處理xml數據,而XmlReader、XmlWriter和它們的派生類使你能夠將xml數據作為數據流處理。
XmlSerializer則提供了另外的方法,它使你能夠將自己的對象串行化和反串行化為xml。串行化數據既能夠讓你像處理文件一樣對數據進行隨機處理,同時又能跳過你不感興趣的數據。
二 主要類庫介紹
   .NET 支持對象xml序列化和反序列化的類庫主要位於命名空間System.Xml.Serialization中。
   1.  XmlSerializer 類
    該類用一種高度松散耦合的方式提供串行化服務。你的類不需要繼承特別的基類,而且它們也不需要實現特別的接口。相反,你只 需在你的類或者這些類的公共域以及讀/寫屬性里加上自定義的特性 XmlSerializer通過反射機制讀取這些特性並用它們將你的類和類成員映射到xml元素和屬性。
   2. XmlAttributeAttribute 類
   指定類的公共域或讀/寫屬性對應xml文件的Attribute。
   例:[XmlAttribute(“type”)] or [XmlAttribute(AttributeName=”type”)]
   3. XmlElementAttribute類
   指定類的公共域或讀/寫屬性對應xml文件的Element。
   例: [XmlElement(“Maufacturer”)]  or [XmlElement(ElementName=”Manufacturer”)]
   4. XmlRootAttribute類
   Xml序列化時,由該特性指定的元素將被序列化成xml的根元素。
   例: [XmlRoot(“RootElement”)]  or [XmlRoot(ElementName = “RootElements”)]
   5. XmlTextAttribute 類
   Xml序列化時,由該特性指定的元素值將被序列化成xml元素的值。一個類只允許擁有一個該特性類的實例,因為xml元素只能有一個值。
   6. XmlIgnoreAttribute類
   Xml序列化時不會序列化該特性指定的元素。
三 實例
   下面例子中的xml schema 描述了一個簡單的人力資源信息,其中包含了xml的大部分格式,如xml 元素相互嵌套, xml元素既有元素值,又有屬性值。
   1. 待序列化的類層次結構
    [XmlRoot("humanResource")]
    public class HumanResource
    {
        #region private data.
        private int m_record = 0;
        private Worker[] m_workers = null;
        #endregion
 
        [XmlAttribute(AttributeName="record")]
        public int Record
        {
            get { return m_record; }
            set { m_record = value; }
        }
 
        [XmlElement(ElementName="worker")]
        public Worker[] Workers
        {
            get { return m_workers; }
            set { m_workers = value; }
        }
}
 
    public class Worker
    {
        #region private data.
        private string m_number = null;
        private InformationItem[] m_infoItems = null;
        #endregion
 
        [XmlAttribute("number")]
        public string Number
        {
            get { return m_number; }
            set { m_number = value; }
        }
 
        [XmlElement("infoItem")]
        public InformationItem[] InfoItems
        {
            get { return m_infoItems; }
            set { m_infoItems = value; }
        }
}
 
    public class InformationItem
    {
        #region private data.
        private string m_name = null;
        private string m_value = null;
        #endregion
 
        [XmlAttribute(AttributeName = "name")]
        public string Name
        {
            get { return m_name; }
            set { m_name = value; }
        }
 
        [XmlText]
        public string Value
        {
            get { return m_value; }
            set { m_value = value; }
        }
}
   2. 序列化生成的xml結構
        <?xml version="1.0" ?>
- <humanResource xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=" http://www.w3.org/2001/XMLSchema"record=" 2">
- <worker number=" 001">
                 <infoItem name=" name"> Michale</infoItem>
                 <infoItem name=" sex"> male</infoItem>
                 <infoItem name=" age"> 25</infoItem>
            </worker>
- <worker number=" 002">
                 <infoItem name=" name"> Surce</infoItem>
                 <infoItem name=" sex"> male</infoItem>
                 <infoItem name=" age"> 28</infoItem>
           </worker>
         </humanResource>
   3. 利用XmlSerializer類進行序列化和反序列化的實現(一般利用緩存機制實現xml文件只解析一次。)
    public sealed class ConfigurationManager
    {
        private static HumanResource m_humanResource = null;
        private ConfigurationManager(){}
 
        public static HumanResource Get(string path)
        {
            if (m_humanResource == null)
            {
                FileStream fs = null;
                try
                {
                    XmlSerializer xs = new XmlSerializer(typeof(HumanResource));
                    fs = new FileStream(path, FileMode.Open, FileAccess.Read);
                    m_humanResource = (HumanResource)xs.Deserialize(fs);
                    fs.Close();
                    return m_humanResource;
                }
                catch
                {
                    if (fs != null)
                        fs.Close();
                    throw new Exception("Xml deserialization failed!");
                }
 
            }
            else
            {
                return m_humanResource;
            }
        }
 
        public static void Set(string path, HumanResource humanResource)
        {
            if (humanResource == null)
                throw new Exception("Parameter humanResource is null!");
           
            FileStream fs = null;
            try
            {
                XmlSerializer xs = new XmlSerializer(typeof(HumanResource));
                fs = new FileStream(path, FileMode.Create, FileAccess.Write);
                xs.Serialize(fs, humanResource);
                m_humanResource = null;
                fs.Close();
            }
            catch
            {
                if (fs != null)
                    fs.Close();
                throw new Exception("Xml serialization failed!");
            }
        }
    }
四 說明
   1. 需要序列化為xml元素的屬性必須為讀/寫屬性;
   2. 注意為類成員設定缺省值,盡管這並不是必須的。

    “序列化”可被定義為將對象的狀態存儲到存儲媒介中的過程。在此過程中,對象的公共字段和私有字段以及類的名稱(包括包含該類的程序集)都被轉換為字節流,然后寫入數據流。在以后“反序列化”該對象時,創建原始對象的精確復本。
一、為什么要選擇序列化
    一個原因是將對象的狀態保持在存儲媒體中,以便可以在以后重新創建精確的副本
    另一個原因是通過值將對象從一個應用程序域發送到另一個應用程序域中
    例如,序列化可用於在 ASP.NET 中保存會話狀態並將對象復制到 Windows 窗體的剪貼板中。遠程處理還可以使用序列化通過值將對象從一個應用程序域傳遞到另一個應用程序域中。
二、如何實現對象的序列化及反序列化
    要實現對象的序列化,首先要保證該對象可以序列化。而且,序列化只是將對象的屬性進行有效的保存,對於對象的一些方法則無法實現序列化的。
    實現一個類可序列化的最簡便的方法就是增加Serializable屬性標記類。如:
    [Serializable()]
    public class MEABlock
    {
        private int m_ID;
        public string Caption;

        public MEABlock()
        {
            ///構造函數
        }
    }
    即可實現該類的可序列化。
    要將該類的實例序列化為到文件中?.NET FrameWork提供了兩種方法:
    1、XML序列化
        使用 XmLSerializer 類,可將下列項序列化。

  • 公共類的公共讀/寫屬性和字段
  • 實現 ICollection 或 IEnumerable 的類。(注意只有集合會被序列化,而公共屬性卻不會。)
  • XmlElement 對象。
  • XmlNode 對象。
  • DataSet 對象。

         要實現上述類的實例的序列化,可參照如下例子:
        MEABlock myBlock = new MEABlock();
        // Insert code to set properties and fields of the object.
        XmlSerializer mySerializer = new XmlSerializer(typeof(MEABlock));
        // To write to a file, create a StreamWriter object.
        StreamWriter myWriter = new StreamWriter("myFileName.xml");
        mySerializer.Serialize(myWriter, MEABlock);
    需要注意的是XML序列化只會將public的字段保存,對於私有字段不予於保存。
    生成的XML文件格式如下:
        <MEABlock>
            <Caption>Test</Caption>
        </MEABlock>
    對於對象的反序列化,則如下:
        MEABlock myBlock;
        // Constructs an instance of the XmlSerializer with the type
        // of object that is being deserialized.
        XmlSerializer mySerializer = new XmlSerializer(typeof(MEABlock));
        // To read the file, creates a FileStream.
        FileStream myFileStream = new FileStream("myFileName.xml", FileMode.Open);
        // Calls the Deserialize method and casts to the object type.
        myBlock = (MEABlock)mySerializer.Deserialize(myFileStream)
    2、二進制序列化
        與XML序列化不同的是,二進制序列化可以將類的實例中所有字段(包括私有和公有)都進行序列化操作。這就更方便、更准確的還原了對象的副本。
        要實現上述類的實例的序列化,可參照如下例子:
        MEABlock myBlock = new MEABlock();
        // Insert code to set properties and fields of the object.
        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream("MyFile.bin",FileMode.Create,FileAccess.Write, FileShare.None);
        formatter.Serialize(stream, myBlock);
        stream.Close();
    對於對象的反序列化,則如下:
        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream("MyFile.bin", FileMode.Open,FileAccess.Read, FileShare.Read);
        MEABlock myBlock = (MEABlock) formatter.Deserialize(stream);
        stream.Close();

三、如何變相實現自定義可視化控件的序列化、反序列化
        對於WinForm中自定義控件,由於繼承於System.Windows.Form類,而Form類又是從MarshalByRefObject繼承的,窗體本身無法做到序列化,窗體的實現基於Win32下GUI資源,不能脫離當前上下文存在。
        當然可以采用變通的方法實現控件的序列化。這里采用的是記憶類模型
        定義記憶類(其實就是一個可序列化的實體類)用於記錄控件的有效屬性,需要序列化控件的時候,只需要將該控件的實例Copy到記憶類,演變成序列化保存該記憶類的操作。
        反序列化是一個逆過程。將數據流反序列化成為該記憶類,再根據該記憶類的屬性生成控件實例。而對於控件的一些事件、方法則可以繼續使用。

 


免責聲明!

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



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