概述反射和序列化(轉)

對於反射與序列化 是比較深入的知識 一般編程中都不需要使用到 尤其是反射 然而對需要用到的人來說 這是一個非常有幫助的功能.
在此我簡介一下反射與序列化 我沒有使用MSDN中的術語或者說是正規的解釋 但不會是錯誤的 所以 如果你對這兩個概念還是模糊的話 建議還是查閱MSDN的解釋.

對於什麼時候要使用這兩種技術呢?
需要知道某個對象的信息 結構 類 屬性 成員變量...等等之類的時候 反射將可以爲你實現 可以理解反射爲解析似的 反射能將某個程序集(包括對象 模塊等)內的幾乎所有信息解析出來 理論上是能夠解析出.Net架構程序的任何信息 並且 反射外部.Net程序也是可能的 並不只是單單處理對象 記住 是一個程序集.

而序列化則是將某個對象改寫成某種信息格式 然後存儲存於某種介質上的過程 當然 某種信息的格式是要能被恢復回來的 這就是反序列化.

先看看反射要如何實現吧 是的 我認爲是如此 將一個程序集加載先 然後用它所提供類來操作這個被加載的程序集 根據不同的類來得到不同的信息.
操 作它的類是非常豐富的 所以 幾乎能得到你所要的所有信息 所有的類與具體的類的用法都可以在MSDN中查到 反射的知識太多 所以 在這裏我將只使用PropertyInfo類的操作來演示 讓它來得到你加載程序集的屬性信息.當然 你還可以用FieldInfo EventInfo等來取得字段與事件信息 似乎舉一反五之類的 你能做到.
 
假定 你現在要反射某個對象的全部屬性(有些敏感的屬性或許是不能得到的).你得先得到一個對象 當然這是必須的 呵 如果你想反射外部程序 Assembly類可以幫你實現 也可將外部程序引用到你的程序中來 這樣對.Net程序都是一樣的.

我們會使用Type類來取得對象的類型
Type type = obj.GetType();

假定obj是你的對象 就這麼類型中存儲着對象的很多信息 GetProperties方法 將會返回這個類型的公共屬性 它返回的是一個PropertyInfo[]類型.GetProperties方法中會有一個篩選參數 可以根據指定的條件篩選數據 參數是BindingFlags枚舉類型 最常用的就是 BindingFlags.Instance 實例成員 BindingFlags.Public 公共成員 BindingFlags.NonPublic 非公共成員.

PropertyInfo[] proInfo = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
如此 就可以得到此對象類型的所有公共屬性了.

//遍歷所有屬性
foreach (PropertyInfo p in proInfo)
{
      Console.WriteLine(p.GetValue(obj, null));//取此屬性的值
}

噢 實在太簡單了 是吧?呵 也許是 反射不會太複雜 但知識點很多 就如我演示的讀取屬性 也只是反射屬性中的一部分 還有更多的對屬性的操作.

如此 可以簡單一點 再說說序列化 爲什麼要將反射與序列化說在一起呢?那就是 如果需要序列化一個對象的話 最快 最優的方法就是先反射對象 再序列化 當然 如果你只是要序列化對象的某些熟悉的信息的話 就沒必要進行反射.

序列化請不要只是認爲轉換成某種格式 它還要能被存儲 能被反序列化.微軟提供了三個(還有嗎?)序列化操作的類BinaryFormatter二進制格式,SoapFormatter以SOAP格 式,XmlSerializer生成XML格式 這些類都是可以序列化與反序列化的 其實它們操作都是一樣的 而XmlSerializer類的功能似乎最弱 判斷一個對象是否可以序列化 可以使用IsSerializable來判斷.定義一個對象可以序列化 是要在類前面加入[Serializable]標識的.ISerializable接口 可以自定義控制序列化與反序列化的過程.

下面將序列化一個MyObject類的實例 使用XmlSerializer類來處理 生成XML文件

[Serializable]
public class MyObject
{
    public int n1;
    public int n2;
    public String str;

    public MyObject()
    {
        n1 = 1;
        n2 = 3;
        str = "sfantasy";
    }
}


private void myW()
{
    MyObject x = new MyObject();
    FileStream f = new FileStream("myFileName.xml", FileMode.Create, FileAccess.Write, FileShare.None);
    XmlSerializer xmls = new XmlSerializer(x.GetType());
    xmls.Serialize(f, x);
    f.Close();
}

生成的XML文檔就是下面這樣的

<?xml version="1.0"?>
<MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <n1>1</n1>
  <n2>3</n2>
  <str>sfantasy</str>
</MyObject>


然後執行反序列化 即可讀出上述XML文件中的數據 來改變現有對象的數據

private void myR()
{
    MyObject myObject = new MyObject();
    myObject.n1 = 0;
    myObject.str = "X";
    XmlSerializer xmls = new XmlSerializer(myObject.GetType());
    FileStream f = new FileStream("myFileName.xml", FileMode.Open);
    myObject = (MyObject)xmls.Deserialize(f);
    f.Close();
}

可以看出 要序列化一個自定義的對象是多麼的簡單~是的 序列化是非常簡單的 至少使用這三個操作類是非常簡單的 而我有說過我理解的序列化含意 所以 在我看來 你不使用這三個操作類 任意將對象使用任意的格式寫入任意的文件 然後能夠再還原讀取 我想 因該也可稱作爲序列化.

對了 使用這三個類時 要記得包含它們的命名空間.
using System.Xml.Serialization;//XmlSerializer
using System.Runtime.Serialization.Formatters.Binary;//BinaryFormatter
using System.Runtime.Serialization.Formatters.Soap;//SoapFormatter


以下的代碼則是對另外兩個序列化操作類的實現

SoapFormatter formatter = new SoapFormatter();//可替換成BinaryFormatter
FileStream stream = new FileStream("myFileName.xml", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, array);
stream.Close();

我提供的示例中 主要是對使用SoapFormatter類序列化系統類型作出了描述 而實現序列化一個系統對象是比實現自定義對象要複雜一些的.有些時候 我們需要序列化一個控件對象 如textBox 而它的類型TextBox中有此屬性(或事件以及其它)信息都多少會有一些不可序列化或不可反序列化的信息(我是指使用微軟提供的三個序列化類操作) 而使用其它方式 都是可以序列化對象的所有信息的 比如手動寫入XML文件.內置的類型又有的沒有加入[Serializable]標識 可以用上面提到的IsSerializable來判斷對象是否能序列化 你又不能修改系統類型的定義 所以 這些信息你需要跳不過操作.

序列化窗體所有控件示例代碼



反射在示例中沒有詳細的代碼 所以 這裏引用微軟一個比較完整的反射代碼 相信聰明的你看了之後...不用再舉一反五了.

// This program lists all the members of the
// System.IO.BufferedStream class.
using System;
using System.IO;
using System.Reflection;

class ListMembers {
    public static void Main(String[] args) {
        // Specifies the class.
        Type t = typeof (System.IO.BufferedStream);
        Console.WriteLine ("Listing all the members (public and non public) of the {0} type", t);

        // Lists static fields first.
        FieldInfo [] fi = t.GetFields (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Fields");
        PrintMembers (fi);

        // Static properties.
        PropertyInfo [] pi = t.GetProperties (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Properties");
        PrintMembers (pi);

        // Static events.
        EventInfo [] ei = t.GetEvents (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Events");
        PrintMembers (ei);

        // Static methods.
        MethodInfo [] mi = t.GetMethods (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Methods");
        PrintMembers (mi);

        // Constructors.
        ConstructorInfo [] ci = t.GetConstructors (BindingFlags.Instance |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Constructors");
        PrintMembers (ci);

        // Instance fields.
        fi = t.GetFields (BindingFlags.Instance | BindingFlags.NonPublic |
         BindingFlags.Public);
        Console.WriteLine ("// Instance Fields");
        PrintMembers (fi);

        // Instance properites.
        pi = t.GetProperties (BindingFlags.Instance | BindingFlags.NonPublic |
         BindingFlags.Public);
        Console.WriteLine ("// Instance Properties");
        PrintMembers (pi);

        // Instance events.
        ei = t.GetEvents (BindingFlags.Instance | BindingFlags.NonPublic |
         BindingFlags.Public);
        Console.WriteLine ("// Instance Events");
        PrintMembers (ei);

        // Instance methods.
        mi = t.GetMethods (BindingFlags.Instance | BindingFlags.NonPublic  
         | BindingFlags.Public);
        Console.WriteLine ("// Instance Methods");
        PrintMembers (mi);

        Console.WriteLine ("\r\nPress ENTER to exit.");
        Console.Read();
    }

    public static void PrintMembers (MemberInfo [] ms) {
        foreach (MemberInfo m in ms) {
            Console.WriteLine ("{0}{1}", "     ", m);
        }
        Console.WriteLine();
    }
}

 

轉自: http://www.cnblogs.com/dewing/archive/2009/11/06/1597683.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章