天天看點

有關.Net中的反射機制的詳解

反射(Reflection)是.Net中的重要機制,通過反射,可以在運作時獲得.Net中的每一個類型(包括類、結構、委托、接口和枚舉等)的成員,包括方法、屬性、事件,以及構造函數等。還可以獲得每個成員的名稱、限定符合參數等。有了反射,即可對每一個類型了如指掌。如果獲得了構造函數的資訊,即可直接建立對象,即使這個對象的類型在編譯時還不知道。

1、.Net可執行應用程式結構

程式代碼在編譯後生成可執行的應用,我們首先要了解這種可執行應用程式的結構。

應用程式結構分為應用程式域-程式集-子產品-類型-成員幾個層次,公共語言運作庫加載器管理應用程式域,這種管理包括将每個程式集加載到相應的應用程式域以及控制每個程式集中類型層次結構的記憶體布局。

程式集包含子產品,而子產品包含類型,類型又包含成員,反射則提供了封裝程式集、子產品和類型的對象。我們可以使用反射動态地建立類的執行個體,将類型綁定到現有對象或從現有對象中擷取類型,然後調用類型的方法或通路其字段和屬性。反射通常具有以下用途。

(1)使用Assembly定義和加載程式集,加載在程式集清單中列出子產品,以及從此程式集中查找類型并建立該類型的執行個體。

(2)使用Module了解包含子產品的程式集以及子產品中的類等,還可以擷取在子產品上定義的所有全局方法或其他特定的非全局方法。

(3)使用ConstructorInfo了解構造函數的名稱、參數、通路修飾符(如pulic 或private)和實作詳細資訊(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法來調用特定的構造函數。

(4)使用MethodInfo了解方法的名稱、傳回類型、參數、通路修飾符(如pulic 或private)和實作詳細資訊(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法來調用特定的方法。

(5)使用FiedInfo了解字段的名稱、通路修飾符(如public或private)和實作詳細資訊(如static)等,并擷取或設定字段值。

(6)使用EventInfo了解事件的名稱、事件處理程式資料類型、自定義屬性、聲明類型和反射類型等,添加或移除事件處理程式。

(7)使用PropertyInfo了解屬性的名稱、資料類型、聲明類型、反射類型和隻讀或可寫狀态等,擷取或設定屬性值。

(8)使用ParameterInfo了解參數的名稱、資料類型、是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。

System.Reflection.Emit命名空間的類提供了一種特殊形式的反射,可以在運作時構造類型反射也可用于建立稱為類型浏覽器的應用程式,使使用者能夠選擇類型,然後檢視有關標明類型的資訊。

此外,Jscript等語言編譯器使用反射來構造符号表。System.Runtime.Serialization命名空間中的類使用反射來通路資料并确定要永久儲存的字段,System.Runtime.Remoting命名空間中的類通過序列化來間接地使用反射

2.樣例

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace ReflectionExample

{

    public class HelloWorld

    {

        string myName = null;

        public HelloWorld(string name)

        {

            myName = name;

        }

        public HelloWorld()

            : this(null)

        { }

        public string Name

        {

            get

            {

                return myName;

            }

        }

        public void SayHello()

        {

            if (myName == null)

            {

                System.Console.WriteLine("Hello World");

            }

            else

            {

                System.Console.WriteLine("Hello," + myName);

            }

        }

    }

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Reflection;

using System.Text;

namespace ReflectionExample

{

    class Test

    {

        [STAThread]

        static void Main(string[] args)

        {

            System.Console.WriteLine("列出程式集中所有的類型");

            //System.Console.ReadKey();

            Assembly a = Assembly.LoadFrom("ReflectionExample.exe");

            Type[] myTypes = a.GetTypes();

            foreach (Type t in myTypes)

            {

                System.Console.WriteLine(t.Name);

            }

            System.Console.ReadLine();

            System.Console.WriteLine("列出HelloWorld中的所有方法");

            Type ht = typeof(HelloWorld);

            MethodInfo[] mif = ht.GetMethods();

            foreach (MethodInfo mf in mif)

            {

                System.Console.WriteLine(mf.Name);

            }

            System.Console.ReadLine();

            System.Console.WriteLine("執行個體化HelloWorld,并調用SayHello方法");

            Object obj = Activator.CreateInstance(ht);

            string[] s = { "zhenlei" };

            object objName = Activator.CreateInstance(ht, s);

            BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static |

                                  BindingFlags.Instance | BindingFlags.DeclaredOnly);

            MethodInfo msayhello = ht.GetMethod("SayHello");

            msayhello.Invoke(obj, null);

            msayhello.Invoke(objName, null);

            System.Console.ReadLine();

        }

    }

}