反射機制(Reflection)通常會涉及到3中場景:
- 運行時反射
- 場景:可以檢索已加載程序集、類型、對象、實例和方法調用的元數據(Metadata)。
- .NET 支持情況:支持
- 僅供靜態分析的反射
- 場景:可以檢索程序集中定義的類型和對象的元數據,而不會產生其他副作用。
- .NET 支持情況:有限的支持
- 反射擴展性
- 場景:在上述兩種場景下擴展元數據。
- .NET 支持情況:支持,但非常復雜
System.Type 是反射模型中的最主要的抽象和入口點。它被用于描述兩種相關但卻不同的概念:基本信息(reference)和定義(definition),并使兩者之間可以互操作。這使得其并不滿足關注點分離(Separation of Concerns)設計原則。
從概念上講,reference 是某種事物的淺顯表述,而 definition 提供更豐富的表述。例如 System.Reflection.Assembly 類代表了程序集的 definitions,而System.Reflection.AssemblyName 類則代表了程序集的 references 。前者暴露了豐富的功能,而后者僅是提供能夠獲取定義的數據。
.NET 4.5 中包含了一些對傳統反射機制的變更。其中最重要的變化是,System.Type 類被分割至兩個獨立的類中:Type 和 TypeInfo。TypeInfo 實例包含 Type 的定義,而 Type 則只關心數據。
- Type:提供對象結構的淺視圖,主要用于持有數據。(reference)
- TypeInfo:提供對象結構的完整視圖,包含對象與父類及子類的關系。(definition)
BCL中的變化
- Assembly.DefinedTypes 屬性返回 TypeInfo。
- 該 API 負責獲取程序集內定義的所有類型。
- Type.BaseType 屬性返回 Type。
- 該 API 盡返回父類型的表述,而不是 definition。
- 父類型有可能被定義在另一個程序集內,這就需要一次程序集加載。
- Object.GetType 方法返回 Type。
- 該 API 返回 Type,因為你僅需要類型的表述。
- 該類型有可能被定義在另一個程序集內,這就需要一次程序集加載。
- C# 關鍵字 typeof 返回 Type。
- 與 Object.GetType 行為相同。
代碼示例
如果你已經在基于 .NET 4.5 的桌面或者 Web 端應用程序中使用了反射機制,原有的 API 仍然可以使用,并且會與新的 API 共存,但新的 API 提供了更輕量級的實現。TypeInfo 使用 IEnumerable 泛型集合來構建元數據,而不是傳統的數組。這使得 TypeInfo 可以支持使用 Lazy 方式遍歷對象元數據,并且可以引入 LINQ 來使查詢更加便捷。
我們先來看下使用傳統 API 來檢索 Type 元數據的方式。Type API 可以提供檢索類型名稱、名空間、類型全名稱、所在模塊等信息。API 結構與 .NET 4.0 中一致。
1 Type studentType = typeof(Student); 2 string studentAssembly = studentType.Assembly.FullName; 3 string studentFullName = studentType.FullName; 4 string studentNameSpace = studentType.Namespace; 5 string studentModule = studentType.Module.FullyQualifiedName;
正如你所看到的,Type 提供了對象結構的基本視圖。如果你需要對類的結構挖掘的更新一些,現在可以使用新的 TypeInfo API。可以通過 GetTypeInfo() 方法從 Type 獲取其 TypeInfo 定義。
我們先定義一個 Student 類:
1 public class Student 2 { 3 public string Name { get; set; } 4 public int Class { get; set; } 5 public int GetTestReport() { return 100; } 6 public event EventHandler Running; 7 }
現在,假如說你需要查看 Student 類中定義的屬性、方法、事件等,可以通過 TypeInfo 提供的 API 獲得。
1 TypeInfo studentInfo = studentType.GetTypeInfo(); 2 IEnumerable<PropertyInfo> declaredProperties = studentInfo.DeclaredProperties; 3 IEnumerable<MethodInfo> declaredMethods = studentInfo.DeclaredMethods; 4 IEnumerable<EventInfo> declaredEvents = studentInfo.DeclaredEvents;
另一個常見的反射方式是查找程序集內定義的所有類型。在 API 變化之后,Assembly.DefinedTypes 將返回一個 TypeInfo 的集合,而不是 Type 數組。
1 Assembly thisAssembly = typeof(Student).GetTypeInfo().Assembly; 2 IEnumerable<TypeInfo> allDefinedTypes = thisAssembly.DefinedTypes;
TypeInfo 除了提供上面描述的屬性,還提供了若干用于獲取元數據信息的方法。
參考資料
- Evolving the Reflection API
- .NET 4.5 TypeInfo Reflection
- Type and TypeInfo, the two new faces of Object Metadata
文章列表