一、程序集的加載
程序集是 .NET Framework 應用程序的構造塊;程序集構成了部署、版本控制、重復使用、激活范圍控制和安全權限的基本單元。
綁定是查找與唯一指定的類型相對應的聲明(即實現)的過程。根據此過程是發生在編譯時還是運行時分為:
a) 靜態綁定:在生成時,編譯器在程序集清單的元數據中記錄靜態引用。
b) 動態綁定:由於調用各種方法而動態構造的,EG: Assembly.Load 方法。
程序集如何加載請參見下面鏈接:
二、程序集的反射
字段、構造器、方法、屬性、事件和嵌套類型都可以被定義成一個類型的成員。FCL(Framework Class Library—框架類庫)定義了一個抽象基類 MemberInfo ,封裝了一組所有類型成員都通用的屬性。
對“動態綁定”的程序集進行成員綁定的規則可通過 Binder 類重寫,作為搜索成員方法的參數傳入;如果此參數傳null,則使用默認綁定規則進行成員綁定同“靜態綁定”。
1. 區分DeclaringType 和ReflectedType
a) ReflectedType 獲取用於獲取 MemberInfo 的此實例的類對象。返回的類對象總是執行反射的Type起點。
b) DeclaringType 獲取聲明該成員的類。
2. GetCustomAttributes()
運行時自定義特性反射模型
-------System.DLL
public class DescriptionAttribute : Attribute
{ ……}
-------System.Web.DLL
internal class MyDescriptionAttribute : DescriptionAttribute
{ ……}
public class LocalizationExtenderProvider
{
[MyDescriptionAttribute(...)]
public CultureInfo GetLanguage(...)
{ ……}
}
如果運行時嘗試使用GetCustomAttributes(Type type) 為附加到 GetLanguage 方法的公共自定義特性類型 DescriptionAttribute 檢索自定義特性,則該運行時將執行下列操作:
a) 運行時檢查 GetCustomAttributes(Type type) 的 DescriptionAttribute 類型參數是否為公共的,判斷是否可見和訪問。
b) 運行時檢查從 DescriptionAttribute 派生的用戶定義類型 MyDescriptionAttribute 在 System.Web.DLL 程序集(它在該程序集中附加到 GetLanguage() 方法)內是否可見和可以訪問。
c) 運行時檢查 MyDescriptionAttribute 的【構造函數】是否在 System.Web.DLL 程序集中可見和可以訪問。
a) 運行時調用帶有自定義特性參數的 MyDescriptionAttribute 的構造函數,然后將新對象返回給調用方。(“只反射上下問”因為不能執行代碼,所以需使用 CustomAttributeData 類訪問自定義特性)
三、獲取Type對象的引用
1) C# typeof 操作符獲得某個類型的 Type 對象,typeof操作符相對其他獲取type方式能獲得更高的性能,操作符用於獲取“早期綁定”的類型信息。
2) Object.GetType 方法返回表示【實例類型】的 Type 對象。可以直接用 o1.GetType()==o2.GetType() 來判斷對象是否屬於同一個類型。
3) System.Reflection.Assembly 對象可先Load尚未加載的程序集,再獲取 Type 對象,包括 Assembly.GetType()、Assembly.GetTypes() 和 Assembly.GetExportedTypes()。
4) Module.GetTypes、Module.GetType 和 Module.FindTypes 方法返回 Type 對象,這些對象表示在某個模塊中定義的類型。第一個方法可用於獲得模塊中定義的所有公共類型和私有類型的 Type 對象的數組。(可通過 Assembly.GetModule()、Assembly.GetModules ()或 Type.Module 屬性來獲得 Module 的實例。)
5) Type類方法:
a) 靜態 Type.GetType 方法可從已加載的程序集中獲取 Type 對象,該對象表示由其完全限定名指定的類型。
b) FindInterfaces 方法返回某個類型所支持的接口類型的篩選后的列表。
c) GetElementType 方法返回表示元素的 Type 對象。
d) GetInterfaces 和 GetInterface 方法返回表示某個類型所支持的接口類型的 Type 對象。
e) GetTypeArray 方法返回表示任意一組對象所指定的類型的 Type 對象數組。這些對象用 Object 類型的數組指定。
f) GetTypeFromProgID 和 GetTypeFromCLSID 方法是為 COM 互操作而提供的。這些方法返回表示 ProgID 或 CLSID 所指定的類型的 Type 對象。
g) GetTypeFromHandle 方法是為COM互操作而提供的。此方法返回表示類句柄所指定的類型的 Type 對象。
h) MakeGenericType 方法返回 Type 對象,該對象表示構造泛型類型,如果該對象的 ContainsGenericParameters 屬性返回 true,則該類型為開放構造類型,否則為封閉構造類型。只能實例化封閉的泛型類型。
i) MakeArrayType、MakePointerType 和 MakeByRefType 方法返回 Type 對象,這些對象分別表示指定類型的數組、指向指定類型的指針以及引用參數的類型(在 C# 中為 ref)。
四、構造類型的實例
1) System.Activator 的 CreateInstance() 靜態方法
注意CLR不要求值類型定義任何構造函數,所以想在不調用構造器的情況下創建值類型的一個實例,必須調用 Activator.CreateInstance() 並且是傳入Type 或傳入Type和Boolean參數的重載。
2) System.Activator 的 CreateInstanceFrom() 靜態方法
通過指定程序集文件名、類型名等參數,內部會根據傳入的程序集文件名調用Assembly的LoadFrom()加載程序集。返回值不是對新對象的一個引用,而是ObjectHandle對象引用(派生自MarshalByRefObject),必須調用ObjectHandle的Unwarp()方法解包對象。
3) System.AppDomain的實例方法
CreateInstance(),CreateInstanceAndUnwrap(),CreateInstanceFrom(),CreateInstanceFromAndUnwrap()。同Activator類方法行為類似。
4) System.Type的 InvokeMember() 實例方法
5) System.Reflection.ConstructorInfo類的Invoke() 實例方法
6) Array的CreateInstance() 靜態方法,創建System.Array及其派生類的實例
7) Delegate的 CreateDelegate() 靜態方法,創建委托(System.MulticastDelegate派生類型)的實例
五、反射的性能
反射機制在提供運行時發現並使用編譯時還不了解的類型及其成員功能時,也存有其缺點:
1.反射會造成編譯時無法保證類型安全性
由於反射要嚴重依賴字符串,所以會喪失編譯時的類型安全性(即:編譯成功,運行報錯)。
2.反射速度慢
a)搜索:使用 System.Reflection 命名空間中的類型掃描程序集的元數據時,反射要不斷的執行字符串的搜索。通常,搜索時不區分大小寫的比較,這會更進一步影響性能。
b)調用:使用反射調用一個成員時。比如調用方法,首先必須將實參打包(pack)成一個數組;在內部,反射必須將這些實參解包(unpack)到線程棧上。此外,在調用方法前,CLR必須檢查實參具有正確的數據類型。最后,CLR必須確保調用者有正確的安全權限來訪問被調用的成員。
1. Type 的 InvokeMember() 實例方法 (出於性能和擴展考慮,推薦直接使用第二種緩存方式)
通過指定:成員名稱、BindingFlags、要在其上調用成員的Object、調用成員的參數數組等參數進行成員調用
該方法會執行兩個操作。
a) 綁定成員:選擇要調用的一個恰當的成員
b) 調用:實際調用成員
2. 一次綁定,多次調用
a) 綁定成員:先通過 Type 的如 GetFields(),GetConstructors(),GetMethods(),GetProperties(),GetEvents() 等方法獲取並緩存這個對象引用,該對象的類型提供了直接訪問特定成員的方法。
b) 調用:
成員類型 |
用於調用成員的方法 |
FieldInfo |
調用GetValue獲取字段的值 調用SetValue設置字段的值 |
PropertyInfo |
調用GetValue調用屬性的get訪問器方法 調用SetValue調用屬性的set訪問器方法 |
EventInfo |
調用AddEventHandler調用事件的add訪問器方法 調用RemoveEventHandler調用事件的remove訪問器方法 |
ConstructorInfo |
調用Invoke構造類型的一個實例,並調用一個構造器 |
MethodInfo |
調用Invoke調用類型的一個方法 |
《反射機制》系列:
參考書籍:ClR via C#(第3版)