前言
在探究地球內部的結構中,如何做到在地球表面不用深入地球內部就可以知道內部的構造呢?其實,向地球發射“地震波”,利用這種方式,可以判斷地球放回的情況,大體上,我們也可以斷定地球內部的構造了,
從這個例子中,通過一個物件的外部去了解物件內部的構造,都是利用了波的反射功能,而利用這種原理,在編程程式時,我們如何也可以實作從物件的外部來了解物件以及程式集內部的結構功能?在.NET中的反射,不僅可以實作外部對內部的了解,也同時可以動態創建出物件并執行其中的方法,
反射是.NET中的重要機制,通過反射,可以在運行時獲得程式或程式集中每一個型別(包括類、結構、委托、介面和列舉等)的成員和成員的資訊,有了反射,即可對每一個型別了如指掌,另外我還可以直接創建物件,即使這個物件的型別在編譯時還不知道,
開始
一、使用的命名空間
System.Reflection
System.Type
System.Reflection.Assembly
二、主要的類
System.Type 類--通過這個類可以訪問任何給定資料型別的資訊,
System.Reflection.Assembly類--它可以用于訪問給定程式集的資訊,或者把這個程式集加載到程式中,
說明
一、System.Type類
System.Type類對反射起著核心的作用,它是一個抽象的基類,Type有與每種資料型別對應的派生類,我們使用這個派生類的物件的方法、欄位、屬性來查找有關該型別的所有資訊,
表示型別宣告:型別別、介面型別、陣列型別、值型別、列舉型別、型別引數、泛型型別定義,以及開放或封閉構造的泛型型別,
從Type中決議型別資訊:

A、判斷給定型別的參考的常用方式:
1. 使用C# typeof運算子
Type t = typeof(string);
2. 使用物件GetType()方法
string s = "i3yuan"; Type t2 = s.GetType();
3.呼叫靜態Type類的靜態方法GetType()
Type t3 = Type.GetType("System.String");
以上三種方式獲取型別Type后,可以應用t來探測string里面的結構
foreach (MemberInfo mi in t.GetMembers()) { Console.WriteLine("{0}/t{1}", mi.MemberType, mi.Name); }
B、Type類屬性:
1.命名空間和型別名
Name 資料型別名
FullName 資料型別的完全限定名(包括命名空間名)
Namespace 定義資料型別的命名空間名
2. 類和委托
Type.IsClass 判斷一個型別是否為類或者委托,符合條件的會有普通的類(包括泛型)、抽象類(abstract class)、委托(delegate)
3. 是否泛型
Type.IsGenericType 屬性可以判斷類或委托是否為泛型型別,
Type.IsGenericTypeDefinition 屬性可以判斷Type是否是未系結引數型別的泛型型別,
Type.IsConstructedGenericType 屬性判斷是否可以此Type創建泛型實體,
4.訪問修飾符
Type.IsPublic 判斷該型別是否是公有的
Type.IsNotPublic
5.密封類、靜態型別、抽象類
Type.IsSealed 判斷該型別是否是密封類,密封類不能被繼承
IsAbstract 指示該型別是否是抽象型別
6. 值型別
Type.IsValueType 判斷一個 Type 是否為值型別,簡單值型別、結構體、列舉,都符合要求,
Type.IsEnum 判斷該型別是否是列舉
Type.IsPrimitive 判斷Type是否為基礎型別
7.介面
Type.IsInterface 判斷該型別是否是介面
8.陣列
IsArray 判斷該型別是否是陣列,GetArrayRank() 獲取陣列的維數,
從Type類決議型別成員結構

一個類由以下一個或多個成員組成:
| 成員型別 | 說明 |
|---|---|
| PropertyInfo | 型別的屬性資訊 |
| FieldInfo | 型別的欄位資訊 |
| ConstructorInfo | 型別的建構式資訊 |
| MethodInfo | 型別的方法 |
| ParameterInfo | 建構式或方法的引數 |
| EventInfo | 型別的事件 |
C、Type類的方法
public class MySqlHelper { public MySqlHelper() { Console.WriteLine("{0}被構造", this.GetType().Name); } public void Query() { Console.WriteLine("{0}.Query", this.GetType().Name); } }
GetConstructor(), GetConstructors():回傳ConstructorInfo型別,用于取得該類的建構式的資訊
MySqlHelper dBHelper = new MySqlHelper(); Type type = dBHelper.GetType(); ConstructorInfo[] constructorInfos= type.GetConstructors(); foreach (var item in constructorInfos) { ParameterInfo[] parameterInfos = item.GetParameters(); foreach (var info in parameterInfos) { Console.WriteLine("查看:" + info.ParameterType.ToString() + " " + info.Name); } }
GetEvent(), GetEvents():回傳EventInfo型別,用于取得該類的事件的資訊
GetField(), GetFields():回傳FieldInfo型別,用于取得該類的欄位(成員變數)的資訊
MySqlHelper nc = new MySqlHelper(); Type t = nc.GetType(); FieldInfo[] fis = t.GetFields(); foreach (FieldInfo fi in fis) { Console.WriteLine(fi.Name); }
GetInterface(), GetInterfaces():回傳InterfaceInfo型別,用于取得該類實作的介面的資訊
GetMember(), GetMembers():回傳MemberInfo型別,用于取得該類的所有成員的資訊
string n = "i3yuan"; Type t = n.GetType(); foreach (MemberInfo mi in t.GetMembers()) { Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name); }
GetMethod(), GetMethods():回傳MethodInfo型別,用于取得該類的方法的資訊
MySqlHelper dBHelper= new MySqlHelper(); Type t = dBHelper.GetType(); MethodInfo[] mis = t.GetMethods(); foreach (MethodInfo mi in mis) { Console.WriteLine(mi.ReturnType+" "+mi.Name); }
GetProperty(), GetProperties():回傳PropertyInfo型別,用于取得該類的屬性的資訊
MySqlHelper dBHelper= new MySqlHelper(); Type t = dBHelper.GetType(); PropertyInfo[] pis = t.GetProperties(); foreach(PropertyInfo pi in pis) { Console.WriteLine(pi.Name); }
可以呼叫這些成員,其方式是呼叫Type的InvokeMember()方法,或者呼叫MethodInfo, PropertyInfo和其他類的Invoke()方法,
用反射生成物件,并呼叫屬性、方法和欄位進行操作
//獲取型別資訊 MySqlHelper dbHelper=new MySqlHelper(); Type type=dbHelper.GetType //創建物件實體化 object DbHelper = Activator.CreateInstance(type); //型別轉換 IDBHelper iDBHelper = (IDBHelper)DbHelper; //方法呼叫 iDBHelper.Query();
二、System.Reflection.Assembly類
Assembly類可以獲得程式集的資訊,也可以動態的加載程式集,以及在程式集中查找型別資訊,并創建該型別的實體,使用Assembly類可以降低程式集之間的耦合,有利于軟體結構的合理化
1. System.Reflection
用于訪問給定程式集的資訊,或者把這個程式集加載到程式中,可以讀取并使用metadata
方法呼叫程序:
1.加載DLL ; 2. 獲取型別資訊 ;3. 創建物件型別 4. 型別轉換 5. 方法呼叫
Assembly assembly = Assembly.Load("Yuan.DB.MySql");//dll名稱無后綴 從當前目錄加載 1 加載dll //完整路徑的加載 可以是別的目錄 加載不會錯,但是如果沒有依賴項,使用的時候會錯 Type type = assembly.GetType("Yuan.DB.MySql.MySqlHelper");//2 獲取型別資訊 object oDBHelper = Activator.CreateInstance(type);//3 創建物件 //oDBHelper.Query();//oDBHelper是objec不能呼叫,但實際上方法是有的 編譯器不認可 IDBHelper iDBHelper = (IDBHelper)oDBHelper;//4 型別轉換 iDBHelper.Query();//5 方法呼叫
方法二:通程序式集的名稱反射
Assembly assembly = Assembly.Load("Yuan.DB.MySql");//dll名稱無后綴 從當前目錄加載 1 加載dll Type type = assembly.GetType("Yuan.DB.MySql.MySqlHelper");//2 獲取型別資訊 object oDBHelper = Activator.CreateInstance(type);//3 創建物件 MethodInfo mi=oDBHelper.GetMethod("Query"); //獲取方法 mi.Invoke(oDBHelper,null);//5 呼叫
總結
1. 作為一個開發人員,在每天都會應用到反射,使用的時候,會反射當前程式的元資料,將所有的方法,類等資訊都全部顯示出來,以便開發人員使用,大大的提高了效率
2. 同時反射提高了程式的靈活性和拓展性,降低耦合,動態加載,允許控制和實作任何類的物件,
3. 當然了,也存在弊端,寫起來復雜,也存在性能問題,用于欄位和方法接入時要遠慢于直接代碼,
參考 檔案 和 《C#圖解教程》
注:搜索關注公眾號【DotNet技術谷】--回復【C#圖解】,可獲取 C#圖解教程檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/61588.html
標籤:C#
上一篇:棄元
