(轉)C#反射機制

在網上查找了不少的資料,可以說大同小異,概念性的東西網上一搜一堆,今天把反射的東西整理了一下,供大家使用,我保證我這裏是最全面的東西,當然也是基礎的東西,在學好了這一切的基礎上,大家可以學習反射的具體插件等應用,老鳥就不用看了。

//首先我們建立一個類庫,將它生成爲HelloWorld.dll,

using System;
using System.Collections.Generic;
using System.Text;

namespace Webtest
{
    using System;

    namespace Webtest
    {

        public interface interface1
        {
            int add();

        }
        public class ReflectTest : interface1
        {

            public String Write;
            private String Writec;

            public String Writea
            {
                get
                {
                    return Write;
                }
                set
                {
                    Write = value;
                }

            }

            private String Writeb
            {
                get
                {
                    return Writec;
                }
                set
                {
                    Writec = value;
                }

            }

            public ReflectTest()
            {
                this.Write = "Write";
                this.Writec = "Writec";
            }

            public ReflectTest(string str1, string str2)
            {
                this.Write = str1;
                this.Writec = str2;

            }

            public string WriteString(string s, int b)
            {
                return "/n這是類庫函數打印的字符串:歡迎您," + s + "---" + b; ;
            }

            public static string WriteName(string s)
            {
                return "/n這是類庫函數打印的字符串:歡迎您光臨," + s;
            }

            public string WriteNoPara()
            {
                return "/n這是類庫函數打印的字符串:您使用的是無參數方法";
            }

            private string WritePrivate()
            {
                return "/n這是類庫函數打印的字符串:私有類型的方法";
            }


            public int add()
            {
                return 5;
            }
        }
    }


}

//然後,建立再建立一個項目引入該HelloWorld.dll,

using System;
using System.Threading;
using System.Reflection;
using Webtest.Webtest;


class Test
{
    delegate string TestDelegate(string value, int value1);

    static void Main()
    {
        //Assembly t = Assembly.LoadFrom("Webtest.dll"); //與下面相同的效果
        Assembly t = Assembly.Load("Webtest");

        Console.Write("Webtest類庫裏有以下類:/n");
        foreach (Type aaa in t.GetTypes())
        {
            Console.Write(aaa.Name + "/n");   //顯示該dll下所有的類
        }

        Module[] modules = t.GetModules();
        Console.WriteLine();
        foreach (Module module in modules)
        {
            Console.WriteLine("模塊名稱:/n" + module.Name);//顯示模塊的名字本例爲"HelloWorld.dll"
        }

        Type a = typeof(Webtest.Webtest.ReflectTest);//得到具體的類的類型,和下面一個效果
        //Type a = t.GetType("Webtest.ReflectTest");
        //Console.Write("模塊裏的類有:" + a.Name + "/n");


        string[] bb ={ "aaaaa", "bbbbb" };
        object obj = Activator.CreateInstance(a, bb); //創建該類的實例,後面的bb爲有參構造函數的參數
        //object obj = t.CreateInstance("Webtest.ReflectTest");//與上面方法相同

        //獲得實例公共方法的集合
        MethodInfo[] miArr = a.GetMethods();
        Console.Write("/n共有方法: /n");
        foreach (MethodInfo mi0 in miArr)
        {
            Console.Write(mi0.Name + "/n"); //顯示所有的共有方法
        }


        MethodInfo mi = a.GetMethod("WriteString");//顯示具體的方法
        object[] aa ={ "使用的是帶有參數的非靜態方法", 2 };
        string s = (string)mi.Invoke(obj, aa); //帶參數方法的調用

        MethodInfo mi1 = a.GetMethod("WriteName");
        String[] aa1 ={ "使用的是靜態方法" };
        string s1 = (string)mi1.Invoke(null, aa1); //靜態方法的調用

        MethodInfo mi2 = a.GetMethod("WriteNoPara");
        string s2 = (string)mi2.Invoke(obj, null); //不帶參數的方法調用

        MethodInfo mi3 = a.GetMethod("WritePrivate", BindingFlags.Instance | BindingFlags.NonPublic);
        string s3 = (string)mi3.Invoke(obj, null); //私有類型方法調用

        //Console.Write(s3);

        //獲得實例公共屬性的集合
        PropertyInfo[] piArr = a.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine("/n顯示所有的屬性:");
        foreach (PropertyInfo pi in piArr)
        {
            Console.WriteLine(pi.Name); //顯示所有的屬性
        }


        PropertyInfo pi1 = a.GetProperty("Writea");
        //pi1.SetValue(obj, "Writea", null);
        //Console.Write(pi1.GetValue(obj,null));

        PropertyInfo pi2 = a.GetProperty("Writeb", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        pi2.SetValue(obj, "Writeb", null);
        //Console.Write(pi2.GetValue(obj, null));

        FieldInfo fi1 = a.GetField("Write");
        //Console.Write(fi1.GetValue(obj));

        //獲得實例公共構造函數的集合
        ConstructorInfo[] ci1 = a.GetConstructors();
        Console.WriteLine("/n顯示所有的構造函數:");
        foreach (ConstructorInfo ci in ci1)
        {
            Console.Write(ci.ToString()+"/n"); //獲得構造函數的形式
        }
       
        //ConstructorInfo asCI = a.GetConstructor(new Type[] { typeof(string), typeof(string) });
        //Console.Write(asCI.ToString());


        Webtest.Webtest.interface1 obj1 = (Webtest.Webtest.interface1)t.CreateInstance("Webtest.ReflectTest");
        Webtest.Webtest.ReflectTest obj2 = (Webtest.Webtest.ReflectTest)t.CreateInstance("Webtest.ReflectTest");
        //Console.Write(obj1.add());典型的工廠模式


        foreach (Type tt in t.GetTypes())
        {
            if (tt.GetInterface("interface1") != null)
            {
                Webtest.Webtest.interface1 obj3 = (Webtest.Webtest.interface1)Activator.CreateInstance(a);
                //Console.Write(obj3.add());
            }
        }


        TestDelegate method = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "WriteString");
        //動態創建委託的簡單例子
        Console.Write(method("str1", 2));
        Console.Read();
    }
}

    在這裏我把我們常用的方法,屬性,等全部整理了出來,大家不要嫌棄亂,靜下心來,自己按照我的分隔一部分一部分的來,保證你對反射的學習,會事半功倍.當然有關於其方法我會繼續補充,想了這麼些就先寫下來吧.

2008年08月16日 星期六 下午 12:21
程序集包含模塊,而模塊包含類型,類型又包含成員。反射則提供了封裝程序集、模塊和類型的對象。您可以使用反射動態地創建類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。然後,可以調用類型的方法或訪問其字段和屬性。反射通常具有以下用途:

使用 Assembly 定義和加載程序集,加載在程序集清單中列出的模塊,以及從此程序集中查找類型並創建該類型的實例。

使用 Module 瞭解如下的類似信息:包含模塊的程序集以及模塊中的類等。您還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。

使用 ConstructorInfo 瞭解以下信息:構造函數的名稱、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。使用 Type 的 GetConstructors 或 GetConstructor 方法來調用特定的構造函數。

使用 MethodInfo 瞭解以下信息:方法的名稱、返回類型、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。使用 Type 的 GetMethods 或 GetMethod 方法來調用特定的方法。

使用 FieldInfo 瞭解以下信息:字段的名稱、訪問修飾符(如 public 或 private)和實現詳細信息(如 static)等;並獲取或設置字段值。

使用 EventInfo 來了解如下的類似信息:事件的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等;並添加或移除事件處理程序。

使用 PropertyInfo 來了解如下的類似信息:屬性的名稱、數據類型、聲明類型、反射類型和只讀或可寫狀態等;並獲取或設置屬性值。

使用 ParameterInfo 來了解如下的類似信息:參數的名稱、數據類型、參數是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。

當您在一個應用程序域的僅反射上下文中工作時,請使用 CustomAttributeData 來了解有關自定義屬性的信息。使用 CustomAttributeData,您不必創建屬性的實例就可以檢查它們。[FROM:MSDN]

通過一個示例來簡要說明:

using System;
using System.Reflection;

namespace testReflection
{
    public delegate void TestDelegate(string info);
    class Program
    {
        static void Main(string[] args)
        {
             //從Dll中加載
             //Assembly ass = Assembly.LoadFile(@"TestReflect.dll");
             //Type myType = ass.GetType("testReflection.Person");
             //object aPerson = ass.CreateInstance("Person");

             //取得類型
            Type myType = Type.GetType ("testReflection.Person");
             //構造函數要用到的參數
            object [] constuctParms = new object[] { "Brad Pitt" };
            //創建實例
            //object TestName = Assembly.GetAssembly(myType).CreateInstance("Person");
            object aPerson = Activator.CreateInstance (myType, constuctParms);

             //使用MethodInfo 和Invoke 調用方法
            MethodInfo displayInfoMethod = myType.GetMethod ("DisplayInfo");
            displayInfoMethod .Invoke(aPerson, new object[] { "Using Invoke to call Method DisplayInfo()" });

            //使用InvokeMember 調用方法
            //調用方法的一些標誌位
             BindingFlags flag = BindingFlags .InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
            myType.InvokeMember("DisplayInfo", flag, null, aPerson, new object[] { "Using InvokeMethod to call DisplayInfo()" });
             //如果方法有返回值
             string name = (string)myType.InvokeMember("getName" , flag, null , aPerson, null );
            System.Console.WriteLine( "call getName(), return: " + name );

            //設置屬性值
            myType.InvokeMember("Age" , BindingFlags.SetProperty, null, aPerson, new object[] { 30 });
            //得到屬性值
             int age = (int)myType.InvokeMember( "Age", BindingFlags.GetProperty, null, aPerson, null);
            System.Console .WriteLine("Get the property of Age : " + Convert.ToString(age));

             //設置字段值
            myType.InvokeMember ("Name", BindingFlags.SetField , null, aPerson , new object[] { "Michal Jodn" });
             //獲取字段值
            string fname = ( string)myType.InvokeMember("Name", BindingFlags.GetField, null , aPerson, null );
            System.Console.WriteLine("Get the Field Value of Name : " + fname);

            myType.InvokeMember("DisplayName", flag, null, aPerson, null);

            //獲得方法集
             MethodInfo[] methods = myType.GetMethods();
            foreach (MethodInfo m in methods) {
                System.Console.WriteLine(m.Name);
            }
            //同樣還有:GetFiedls()、GetProperties()、GetEvents()等方法

            //使用Delegate
            //此方法是靜態的,所以必須提供委託類型。
            TestDelegate dg = (TestDelegate)Delegate.CreateDelegate( typeof(testReflection.TestDelegate), aPerson, "DisplayInfo");
            dg ("Test Delegate by call DisplayInfo()");
            
           
            //獲得解決方案的所有Assembly
            Assembly[] AX = AppDomain.CurrentDomain.GetAssemblies();
            //遍歷顯示每個Assembly的名字
            foreach (object var in AX ) {
                Console.WriteLine ("Assembly的名字:"+var.ToString());               
            }
             //使用一個已知的Assembly名稱,來創建一個Assembly
             //通過CodeBase屬性顯示最初指定的程序集的位置
            Console.WriteLine ("最初指定的程序集TestReflection的位置:" + Assembly.Load("TestReflection").CodeBase);

            System.Console.ReadLine();

         }
    }  

    public class Person
    {
        public string Name;
        private int _Age;
        public int Age
        {
            get
            {
                 return _Age;
             }
            set
            {
                _Age = value;
            }
        }

        public Person (string Name)
         {
            this.Name = Name;
        }
        public void DisplayInfo(string info)
        {
            System.Console.WriteLine(info );
            System.Console.WriteLine( "called sucessfully!");
        }
         public void DisplayName()
        {
            System .Console.WriteLine(Name);
        }
        public string getName()
        {
             return Name;
        }

    }
}
說明:
使用反射動態調用類成員,需要Type類的一個方法:InvokeMember。對該方法的聲明如下:

public object InvokeMember(
   string name,
   BindingFlags invokeAttr,
   Binder binder,
   object target,
   object[] args
);

參數

name
String,它包含要調用的構造函數、方法、屬性或字段成員的名稱。
- 或 -
空字符串 (""),表示調用默認成員。

invokeAttr
一個位屏蔽,由一個或多個指定搜索執行方式的 BindingFlags 組成。訪問可以是 BindingFlags 之一,如 Public、NonPublic、Private、InvokeMethod 和 GetField 等。不需要指定查找類型。如果省略查找類型,則將應用 BindingFlags.Public | BindingFlags.Instance。

binder
一個 Binder 對象,該對象定義一組屬性並啓用綁定,而綁定可能涉及選擇重載方法、強制參數類型和通過反射調用成員。
- 或 -
若爲空引用(Visual Basic 中爲 Nothing),則使用 DefaultBinder。

target
在其上調用指定成員的 Object。

args
包含傳遞給要調用的成員的參數的數組。

返回值
表示被調用成員的返回值的 Object。

下列 BindingFlags 篩選標誌可用於定義包含在搜索中的成員:

爲了獲取返回值,必須指定 BindingFlags.Instance 或 BindingFlags.Static。
指定 BindingFlags.Public 可在搜索中包含公共成員。
指定 BindingFlags.NonPublic 可在搜索中包含非公共成員(即私有成員和受保護的成員)。
指定 BindingFlags.FlattenHierarchy 可包含層次結構上的靜態成員。

下列 BindingFlags 修飾符標誌可用於更改搜索的執行方式:
BindingFlags.IgnoreCase,表示忽略 name 的大小寫。
BindingFlags.DeclaredOnly,僅搜索 Type 上聲明的成員,而不搜索被簡單繼承的成員。

可以使用下列 BindingFlags 調用標誌表示要對成員採取的操作:
CreateInstance,表示調用構造函數。忽略 name。對其他調用標誌無效。
InvokeMethod,表示調用方法,而不調用構造函數或類型初始值設定項。
對 SetField 或 SetProperty 無效。
GetField,表示獲取字段值。對 SetField 無效。
SetField,表示設置字段值。對 GetField 無效。
GetProperty,表示獲取屬性。對 SetProperty 無效。
SetProperty 表示設置屬性。對 GetProperty 無效。

發佈了18 篇原創文章 · 獲贊 4 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章