(一)在運行期間處理和檢查代碼 自定義特性允許把自定義元數據與程式元素關聯起來。反射是一個普通術語,它描述了在運行過程中檢查和處理程式元素的功能。例如,反射允許完成的任務: 枚舉類型的成員 實例化新對象 執行對象的成員 查找程式集的信息 檢查應用於某種類型的自定義特性 創建和編譯新程式集 (二)自定 ...
(一)在運行期間處理和檢查代碼
自定義特性允許把自定義元數據與程式元素關聯起來。反射是一個普通術語,它描述了在運行過程中檢查和處理程式元素的功能。例如,反射允許完成的任務:
- 枚舉類型的成員
- 實例化新對象
- 執行對象的成員
- 查找程式集的信息
- 檢查應用於某種類型的自定義特性
- 創建和編譯新程式集
(二)自定義特性
使自定義特性非常強大的因素時使用反射,代碼可以讀取這些元數據,使用它們在運行期間作出決策。
1、編寫自定義特性
定義一個FieldName特性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FieldNameAttribute : Attribute
{
private string name;
public FieldNameAttribute(string name)
{
this.name = name;
}
}
(1)AttributeUsage特性
特性類本身用一個特性——System.AttributeUsage特性來標記。AttributeUsage第一個參數用於標識自定義特性可以應用到那些類型的程式元素上,其類型是枚舉類型AttrubuteTargets。
當應用類型超過1個時,可以用OR運算符連接:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
AllowMultiple屬性用於指定該特性是否可以多次應用於同一項上,當設置為false,以下編碼會報錯:
[FieldName("我的屬性1")] [FieldName("我的屬性2")] public int MyProperty { get; set; }
Inherited屬性用於指示使用該特性的類或類成員能否由派生類或重寫成員繼承。
(2)指定特性參數
編譯器會檢查傳遞給特性的參數,並查找該特性中帶這些參數的構造函數。一半僅提供一個構造函數,使用屬性來定義任何其他可選參數。
(3)指定特性的可選參數
另一種語法,可把可選參數添加到特性中。這種語法指定可選參數的名稱和值,它通過特性類中的公共屬性或欄位起作用。例如上述代碼中AttributeUsage特性使用的AllowMultiple和Inherited就是使用的這種語法。
(三)反射
通過System.Type類可以訪問關於任何數據類型的信息。System.Reflection.Assembly類可以用於訪問給定程式集的相關信息,或者把這個程式集載入到程式中。
1、System.Type類
Type有與每種數據類型對應的派生類。獲取指定任何給定類型的Type引用有3中常用方式:
使用C#的typeof運算符:
Type type = typeof(double);
使用GetType()方法(所有的類都會從System.Object繼承這個方法):
double d = 10.0; Type type = d.GetType();
使用Type類的靜態方法GetType():
Type type = Type.GetType("System.Double");
(1)Type的屬性
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Type intType = typeof(int); 6 Console.WriteLine("當前類型的類型名:"+intType.Name); 7 Console.WriteLine("當前類型的類型完全限定名:" + intType.FullName); 8 Console.WriteLine("當前類型的名稱空間名:" + intType.Namespace); 9 Console.WriteLine("當前類型的直接基類名:" + intType.BaseType); 10 Console.WriteLine("當前類型的.NET運行庫中映射到的類型:" + intType.UnderlyingSystemType); 11 Console.WriteLine("是否為數組的:" + intType.IsArray); 12 Console.WriteLine("是否為值類型:" + intType.IsValueType); 13 } 14 } 15 public class MyBaseClass { } 16 public class MyClass : MyBaseClass { }
運行以上代碼,結果如下:
還有很多IsXXX來判斷是否為某種類型。
(2)方法
System.Type類的大多數方法都用於獲取對應數據類型的成員信息:構造函數、屬性、方法和事件。尾碼加‘s’的表示獲取當前數據類型中所有的成員相關信息,不加則只獲取數據類型中一個成員的相關信息。
Type intType = typeof(int); var method = intType.GetMethod("GetHashCode"); var methods = intType.GetMethods(); foreach (var item in methods) {}
System.Type類還包含有GetConstructor()方法和GetConstructors()等。
2、Assembly類
Assembly類在System.Reflection名稱空間中定義,它允許訪問給定程式集的元數據,它也包含可以載入和執行程式集(假定該程式集是可執行的)的方法。可以使用靜態成員Assembly.Load()或Assembly.LoadFrom()。
使用Load()載入:
Assembly assembly1 = Assembly.Load("程式集名");
使用LoadFrom()載入:
Assembly assembly2 = Assembly.LoadFrom("程式集實際路徑");
載入程式集後就可以使用它的各種屬性進行查詢:
string name = assembly1.FullName;
(1)獲取在程式集中定義的類型的詳細信息
Assembly類的一個功能是它可以獲得在相應程式集中定義的所有類型的詳細信息,只要調用Assembly.GetTypes()方法,就可以返回一個包含所有類型的詳細信息的System.Type引用數組。
Type[] typeArray = assembly.GetTypes();
(2)獲取自定義特性的詳細信息
如果要確定程式集從整體上關聯了什麼自定義特性,就需要調用Attribute類的一個靜態方法GetCustomAttributes()。
Attribute[] definedAttributes = Attribute.GetCustomAttributes(assembly);