首先我們可以先來了解下什么是反射
Reflection,中文翻譯為反射。
這是.Net中獲取運行時類型信息的方式,.Net的應用程序由幾個部分:‘程序集(Assembly)’、‘模塊(Module)’、‘類型 (class)’組成,而反射提供一種編程的方式,讓程序員可以在程序運行期獲得這幾個組成部分的相關信息,例如:
Assembly類可以獲得正在運行的裝配件信息,也可以動態的加載裝配件,以及在裝配件中查找類型信息,並創建該類型的實例。
Type類可以獲得對象的類型信息,此信息包含對象的所有要素:方法、構造器、屬性等等,通過Type類可以得到這些要素的信息,並且調用之。
MethodInfo包含方法的信息,通過這個類可以得到方法的名稱、參數、返回值等,並且可以調用之。
諸如此類,還有FieldInfo、EventInfo等等,這些類都包含在System.Reflection命名空間下。
程序代碼在編譯后生成可執行的應用,我們要了解這種可執行應用程序的結構。
程序集包含模塊,而模塊包含類型,類型又包含成員。
反射則提供了封裝程序集、模塊和類型的對象。
您可以使用反射動態地創建類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。
然后,可以調用類型的方法或訪問其字段和屬性。
反射通常具有以下用途:
1.使用 Assembly 定義和加載程序集,加載在程序集清單中列出的模塊,以及從此程序集中查找類型並創建該類型的實例。
2.使用 Module 了解如下的類似信息:包含模塊的程序集以及模塊中的類等。您還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。
3.使用 ConstructorInfo 了解以下信息:構造函數的名稱、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。使用 Type 的 GetConstructors 或 GetConstructor 方法來調用特定的構造函數。
4.使用 MethodInfo 了解以下信息:方法的名稱、返回類型、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。使用 Type 的 GetMethods 或 GetMethod 方法來調用特定的方法。
5.使用 FieldInfo 了解以下信息:字段的名稱、訪問修飾符(如 public 或 private)和實現詳細信息(如 static)等;並獲取或設置字段值。
6.使用 EventInfo 來了解如下的類似信息:事件的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等;並添加或移除事件處理程序。
7.使用 EventInfo 來了解如下的類似信息:事件的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等;並添加或移除事件處理程序。
8.使用 ParameterInfo 來了解如下的類似信息:參數的名稱、數據類型、參數是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。
9.當您在一個應用程序域的僅反射上下文中工作時,請使用 CustomAttributeData 來了解有關自定義屬性的信息。使用 CustomAttributeData,您不必創建屬性的實例就可以檢查它們。
下面我們通過實例代碼來看一下:
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; } }
首先我創建了一個控制台的應用程序,然后定義一個實體Person類。
接下來就來看看Main函數中的實現代碼吧。
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(); }
說明:
您也可以直接下載代碼進行調試查看 示例代碼
使用反射動態調用類成員,需要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 無效。