在探究地球內部的結構中,如何作到在地球表面不用深刻地球內部就能夠知道內部的構造呢?其實,向地球發射「地震波」。利用這種方式,能夠判斷地球放回的狀況,大致上,咱們也能夠判定地球內部的構造了。編程
從這個例子中,經過一個對象的外部去了解對象內部的構造,都是利用了波的反射功能。而利用這種原理,在編程程序時,咱們如何也能夠實現從對象的外部來了解對象以及程序集內部的結構功能?在.NET中的反射,不只能夠實現外部對內部的瞭解,也同時能夠動態建立出對象並執行其中的方法。api
反射是.NET中的重要機制,經過反射,能夠在運行時得到程序或程序集中每個類型(包括類、結構、委託、接口和枚舉等)的成員和成員的信息。有了反射,便可對每個類型瞭如指掌。另外我還能夠直接建立對象,即便這個對象的類型在編譯時還不知道。 數組
1、使用的命名空間函數
System.Reflection
System.Type
System.Reflection.Assembly性能
2、主要的類this
System.Type 類--經過這個類能夠訪問任何給定數據類型的信息。
System.Reflection.Assembly類--它能夠用於訪問給定程序集的信息,或者把這個程序集加載到程序中。spa
1、System.Type類3d
System.Type類對反射起着核心的做用。它是一個抽象的基類,Type有與每種數據類型對應的派生類,咱們使用這個派生類的對象的方法、字段、屬性來查找有關該類型的全部信息。code
表示類型聲明:類類型、接口類型、數組類型、值類型、枚舉類型、類型參數、泛型類型定義,以及開放或封閉構造的泛型類型。對象
從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();
2、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#圖解教程文件