使用反射(Reflection)使得程式在運行過程中可以動態的獲取對象或類型的類型信息,然後調用該類型的方法和構造函數,或訪問和修改該類型的欄位和屬性;可以通過晚期綁定技術動態的創建類型的實例;可以獲取程式集中的所有類型信息;可以在動態構建新類型;還可以檢索元素所添加的特性; ※反射相關的類基本都位 ...
使用反射(Reflection)使得程式在運行過程中可以動態的獲取對象或類型的類型信息,然後調用該類型的方法和構造函數,或訪問和修改該類型的欄位和屬性;可以通過晚期綁定技術動態的創建類型的實例;可以獲取程式集中的所有類型信息;可以在動態構建新類型;還可以檢索元素所添加的特性;
※反射相關的類基本都位於命名空間System.Reflection中;
※動態構建新類型的類位於命名空間System.Reflection.Emit中;
一、訪問或修改類型的實例、靜態欄位:
public class MyClass { public int myField; public static int myStaticField; } //使用方式: //訪問或修改類型的實例欄位myField MyClass myObj = new MyClass() { myField = 1 }; //創建實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() FieldInfo fieldInfo = myType.GetField("myField"); //獲取類型中指定的欄位信息 Console.WriteLine((int)fieldInfo.GetValue(myObj)); //1,獲取實例欄位的值 fieldInfo.SetValue(myObj, 2); //給實例欄位賦值 //訪問或修改類型的靜態欄位myStaticField FieldInfo staticFieldInfo = myType.GetField("myStaticField"); //獲取類型中指定的欄位信息 Console.WriteLine(staticFieldInfo.GetValue(null)); //0,獲取靜態欄位的值 staticFieldInfo.SetValue(null, 2); //給靜態欄位賦值
※與直接賦值相比,使用反射賦值用時約長75倍,使用以下代碼多次測試:
public class MyClass { public int myField; } class Program { static void Main(string[] args) { Stopwatch stopwatch = new Stopwatch(); MyClass myObj = new MyClass() { myField = 1 }; Type myType = typeof(MyClass); FieldInfo fieldInfo = myType.GetField("myField"); stopwatch.Start(); for (int i = 0; i < 10_000_000; i++) { fieldInfo.SetValue(myObj, 2); } stopwatch.Stop(); Console.WriteLine($"使用反射賦值1千萬次耗時:{stopwatch.ElapsedMilliseconds}"); stopwatch.Reset(); stopwatch.Start(); for (int i = 0; i < 10_000_000; i++) { myObj.myField = 2; } stopwatch.Stop(); Console.WriteLine($"直接賦值1千萬次耗時:{stopwatch.ElapsedMilliseconds}"); Console.Read(); } }
二、訪問或修改類型的實例、靜態屬性:
public class MyClass { public int MyProperty { get; set; } public static int MyStaticProperty { get; set; } }
//使用方式: //訪問或修改類型的實例屬性MyProperty MyClass myObj = new MyClass() { MyProperty = 1 }; //創建實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() PropertyInfo propertyInfo = myType.GetProperty("MyProperty"); //獲取類型中指定的屬性信息 Console.WriteLine((int)propertyInfo.GetValue(myObj, null)); //1,獲取實例屬性的值 propertyInfo.SetValue(myObj, 2, null); //給實例屬性賦值 //訪問或修改類型的靜態屬性MyStaticProperty PropertyInfo staticPropertyInfo = myType.GetProperty("MyStaticProperty"); //獲取類型中指定的屬性信息 Console.WriteLine(staticPropertyInfo.GetValue(null, null)); //0,獲取靜態屬性的值 staticPropertyInfo.SetValue(null, 2); //給靜態屬性賦值
※在使用反射給屬性賦值時,如果該屬性不具有set訪問器,則會拋出異常ArgumentException;
三、調用類型的方法:
public class MyClass { public void MyFunc(int num) { Console.WriteLine("MyFunc(int num) execute, the parameter is: " + num); } public static void MyStaticFunc(int num) { Console.WriteLine("MyStaticFunc(int num) execute, the parameter is: " + num); } }
//使用方式: //調用類型的實例方法MyFunc MyClass myObj = new MyClass(); //創建實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() MethodInfo methodInfo = myType.GetMethod("MyFunc"); //獲取類型中指定的方法信息 methodInfo.Invoke(myObj, new object[] { 10 }); //調用實例方法,並傳入參數,無參傳null //MyFunc(int num) execute, the parameter is: 10 //調用類型的實例方法MyStaticFunc MethodInfo staticMethodInfo = myType.GetMethod("MyStaticFunc"); //獲取類型中指定的方法信息 staticMethodInfo.Invoke(null, new object[] { 20 }); //調用靜態方法,並傳入參數,無參傳null //MyStaticFunc(int num) execute, the parameter is: 20
四、調用類型的構造函數同時創建實例:
public class MyClass { public MyClass() { Console.WriteLine("MyClass() execute."); } public MyClass(int num) { Console.WriteLine("MyClass(int num) execute, the parameter is: " + num); } }
//使用方式: //調用無參的構造函數 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() ConstructorInfo constructorInfo = myType.GetConstructor(new Type[] { }); //獲取類型中指定的構造函數信息,傳入該構造函數的參數列表的類型數組,無參傳空數組 MyClass myObj = constructorInfo.Invoke(null) as MyClass; //通過調用構造函數創建實例,無參傳null //MyClass() execute. //調用帶參數的構造函數 constructorInfo = myType.GetConstructor(new Type[] { typeof(int) }); //獲取類型中指定的構造函數信息,傳入該構造函數的參數列表的類型數組 myObj = constructorInfo.Invoke(new object[] { 20 }) as MyClass; //通過調用構造函數創建實例,並傳入參數 //MyClass(int num) execute, the parameter is: 20
※也可以使用Type類中的實例方法InvokeMember()來調用指定成員;
五、使用反射查找特性:
1.如果元素使用了特性,在沒有檢索並對其進行操作前該特性沒有任何價值,可以使用反射在程式運行過程中獲取元素添加的特性然後對其進行操作,使用特性基類Attribute中的靜態方法GetCustomAttributes(MemberInfo element)或命名空間System.Reflection中的擴展方法GetCustomAttributes(this MemberInfo element)來獲取類型或成員的所有特性信息:
Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass)); //IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes(); foreach (var item in attributes) { if (item is MyselfAttribute) { MyselfAttribute attribute = item as MyselfAttribute; Console.WriteLine(attribute .ClassName + " " + attribute .Author); //MyClass Me } }
2.這兩個方法都有對應的重載方法,可以傳入要檢索的指定特性的類型,這樣即可得到元素中所有指定類型的特性信息:
Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass), typeof(MyselfAttribute)); //IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes(typeof(MyselfAttribute)); foreach (var item in attributes) { MyselfAttribute attribute = item as MyselfAttribute; Console.WriteLine(attribute.ClassName + " " + attribute.Author); //MyClass Me }
※如果未找到任何特性或指定類型的特性,這些方法會返回一個空數組;
3.也可以使用基類Attribute中的靜態方法GetCustomAttribute(MemberInfo element, Type attributeType)或命名空間System.Reflection中的擴展方法GetCustomAttribute(this MemberInfo element, Type attributeType)來獲取類型或成員的指定特性信息;
※如果未找到指定類型的特性,會返回null;
※在檢索的元素中存在多個相同的指定類型的特性時,會拋出異常Reflection.AmbiguousMatchException;
類型信息、晚期綁定、動態創建類型等會在下一篇中介紹。
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的認可是我寫作的最大動力!
作者:Minotauros
出處:https://www.cnblogs.com/minotauros/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。