10分鐘教你理解反射
阿新 • • 發佈:2019-06-11
什麼是反射?
反射反射,程式設計師的快樂,在.Net領域程式設計中,反射是無處不在的,MVC、ASP.Net、各種ORM、IOC、AOP幾乎所有的框架都離不開反射。反編譯工具使用的底層技術用的不是反射,是一種逆向工程。
反射(Reflection、System.Reflection),是.Net Framework提供的一個幫助類庫,可以讀取並使用Metadata中描述的資料資訊。元資料(Metadata),描述了dll/exe裡面的各種資訊,又稱中介資料、中繼資料,為描述資料的資料(data about data),主要是描述資料屬性(property)的資訊,用來支援如指示儲存位置、歷史資料、資源查詢、檔案記錄等功能。
反射的優缺點:
優點:動態—在不破壞原有程式的情況下,可對程式進行良好的擴充套件。Eg:我們有這樣一需求,專案在最初的時候用的是Mysql資料庫,由於專案情況變化需要更換成SqlServer資料庫。面對這種專案的需求,傳統的解決方法是在專案中新增新的SqlServer資料庫訪問程式碼,將資料庫訪問實現層更改為SqlServer,最後編譯原始碼並重新發布。
傳統解決方法示例虛擬碼如下:
1 IDBHelper iDBHelper = new MySqlHelper(); 2 IDBHelper iDBHelper = new SqlServerHelper(); 3 iDBHelper.Query();
使用反射的示例程式碼:
1 namespace ReflectionDemo 2 { 3 /// <summary> 4 /// 反射工廠 5 /// </summary> 6 public class SimpleFactory 7 { 8 //讀取配置檔案 9 private static string IDBHelperConfig = ConfigurationManager.AppSettings["IDBHelperConfig"]; 10 //獲取需要載入的dll名稱 11 private static string DllName = IDBHelperConfig.Split(',')[0]; 12 //獲取需要的型別名稱 13 private static string TypeName = IDBHelperConfig.Split(',')[1]; 14 /// <summary> 15 /// 通過反射動態載入與型別名稱相匹配的例項 16 /// </summary> 17 /// <returns></returns> 18 public static IDBHelper CreateInstance() 19 { 20 Assembly assembly = Assembly.Load(DllName); 21 Type type = assembly.GetType(TypeName); 22 object oDBHelper = Activator.CreateInstance(type); 23 IDBHelper iDBHelper = oDBHelper as IDBHelper; 24 return iDBHelper; 25 } 26 } 27 }
<add key="IDBHelperConfig" value="MySqlDb,MySqlDb.MySqlHelper"/>
IDBHelper iDBHelper = SimpleFactory.CreateInstance(); iDBHelper.Query();
通過反射實現了程式的可配置,通過修改配置檔案就可以自動切換實現類,實現類必須是事先已有的, 沒有將實現類固定,而是通過配置檔案執行,通過反射建立的。可擴充套件:完全不修改原有程式碼,只是增加新的實現、修改配置檔案,就可以支援新功能。這就是反射的動態特性。
缺點:使用麻煩、避開編譯器檢查導致運程式行時異常變多、效能問題。
通過反射呼叫建構函式
1 namespace SqlServerDb 2 { 3 4 /// <summary> 5 /// 反射測試類 6 /// </summary> 7 public class ReflectionTest 8 { 9 #region Identity 10 /// <summary> 11 /// 無參建構函式 12 /// </summary> 13 public ReflectionTest() 14 { 15 Console.WriteLine("這裡是{0}無引數建構函式", this.GetType()); 16 } 17 18 /// <summary> 19 /// 帶引數建構函式 20 /// </summary> 21 /// <param name="name"></param> 22 public ReflectionTest(string name) 23 { 24 Console.WriteLine("這裡是{0} 有引數【string】建構函式", this.GetType()); 25 } 26 27 public ReflectionTest(int id) 28 { 29 Console.WriteLine("這裡是{0} 有引數【int】建構函式", this.GetType()); 30 } 31 #endregion 32 33 #region Method 34 /// <summary> 35 /// 無參方法 36 /// </summary> 37 public void Show1() 38 { 39 Console.WriteLine("這裡是{0}的Show1", this.GetType()); 40 } 41 /// <summary> 42 /// 有引數方法 43 /// </summary> 44 /// <param name="id"></param> 45 public void Show2(int id) 46 { 47 48 Console.WriteLine("這裡是{0}的Show2", this.GetType()); 49 } 50 /// <summary> 51 /// 過載方法之一 52 /// </summary> 53 /// <param name="id"></param> 54 /// <param name="name"></param> 55 public void Show3(int id, string name) 56 { 57 Console.WriteLine("這裡是{0}的Show3", this.GetType()); 58 } 59 /// <summary> 60 /// 過載方法之二 61 /// </summary> 62 /// <param name="name"></param> 63 /// <param name="id"></param> 64 public void Show3(string name, int id) 65 { 66 Console.WriteLine("這裡是{0}的Show3_2", this.GetType()); 67 } 68 /// <summary> 69 /// 過載方法之三 70 /// </summary> 71 /// <param name="id"></param> 72 public void Show3(int id) 73 { 74 Console.WriteLine("這裡是{0}的Show3_3", this.GetType()); 75 } 76 /// <summary> 77 /// 過載方法之四 78 /// </summary> 79 /// <param name="name"></param> 80 public void Show3(string name) 81 { 82 Console.WriteLine("這裡是{0}的Show3_4", this.GetType()); 83 } 84 85 /// <summary> 86 /// 過載方法之五 87 /// </summary> 88 public void Show3() 89 { 90 Console.WriteLine("這裡是{0}的Show3_1", this.GetType()); 91 } 92 93 /// <summary> 94 /// 私有方法 95 /// </summary> 96 /// <param name="name"></param> 97 private void Show4(string name) 98 { 99 Console.WriteLine("這裡是{0}的Show4", this.GetType()); 100 } 101 102 /// <summary> 103 /// 靜態方法 104 /// </summary> 105 /// <param name="name"></param> 106 public static void Show5(string name) 107 { 108 Console.WriteLine("這裡是{0}的Show5", typeof(ReflectionTest)); 109 } 110 #endregion 111 } 112 }
1 Assembly assembly = Assembly.Load("SqlServerDb"); 2 Type type = assembly.GetType("SqlServerDb.ReflectionTest"); 3 foreach (ConstructorInfo ctor in type.GetConstructors()) 4 { 5 Console.WriteLine($"ctor.Name:{ctor.Name}"); 6 foreach (var parameter in ctor.GetParameters()) 7 { 8 Console.WriteLine($"ParameterType:{parameter.ParameterType},parameterName: {parameter.Name}"); 9 } 10 } 11 object oTest1 = Activator.CreateInstance(type); 12 object oTest2 = Activator.CreateInstance(type, new object[] { 123 }); 13 object oTest3 = Activator.CreateInstance(type, new object[] { "陌殤" });
反射破壞單例
1 //反射破壞單例---就是反射呼叫私有建構函式 2 Assembly assembly = Assembly.Load("SqlServerDb"); 3 Type type = assembly.GetType("SqlServerDb.Singleton"); 4 Singleton singletonA = (Singleton)Activator.CreateInstance(type, true); 5 Singleton singletonB = (Singleton)Activator.CreateInstance(type, true); 6 Console.WriteLine($"{object.ReferenceEquals(singletonA, singletonB)}");
反射呼叫泛型類
namespace SqlServerDb { /// <summary> /// 泛型測試類 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="W"></typeparam> /// <typeparam name="X"></typeparam> public class GenericClass<T, W, X> { public GenericClass() { Console.WriteLine("GenericClass<T, W, X>的建構函式被呼叫了"); } public void Show(T t, W w, X x) { Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name); } } /// <summary> /// 泛型測試方法 /// </summary> public class GenericMethod { public GenericMethod() { Console.WriteLine("GenericMethod類的建構函式被呼叫了。"); } public void Show<T, W, X>(T t, W w, X x) { Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name); } } public class GenericDouble<T> { public void Show<W, X>(T t, W w, X x) { Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name); } } }
1 Assembly assembly = Assembly.Load("SqlServerDb"); 2 Type type = assembly.GetType("SqlServerDb.GenericClass`3"); 3 GenericClass<string, int, DateTime> genericClass = new GenericClass<string, int, DateTime>(); 4 //genericClass.Show("12", 1, DateTime.Now); 5 //object oGeneric = Activator.CreateInstance(type); 6 Type typeMake = type.MakeGenericType(new Type[] { typeof(string), typeof(int), typeof(DateTime) }); 7 object oGeneric = Activator.CreateInstance(typeMake);
反射呼叫泛型方法
Assembly assembly = Assembly.Load("SqlServerDb"); Type type = assembly.GetType("SqlServerDb.GenericMethod"); object oGeneric = Activator.CreateInstance(type);
如果反射建立物件之後,知道方法名稱,怎麼樣不做型別轉換,直接呼叫方法?
1 2 Assembly assembly = Assembly.Load("SqlServerDb"); 3 Type type = assembly.GetType("SqlServerDb.ReflectionTest"); 4 object oTest = Activator.CreateInstance(type); 5 foreach (var method in type.GetMethods()) 6 { 7 Console.WriteLine(method.Name); 8 foreach (var parameter in method.GetParameters()) 9 { 10 Console.WriteLine($"{parameter.Name} {parameter.ParameterType}"); 11 } 12 } 13 { 14 ReflectionTest reflection = new ReflectionTest(); 15 reflection.Show1(); 16 } 17 { 18 MethodInfo method = type.GetMethod("Show1"); 19 //if() 20 method.Invoke(oTest, null); 21 } 22 { 23 MethodInfo method = type.GetMethod("Show2"); 24 method.Invoke(oTest, new object[] { 123 }); 25 } 26 { 27 MethodInfo method = type.GetMethod("Show3", new Type[] { }); 28 method.Invoke(oTest, null); 29 } 30 { 31 MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(int) }); 32 method.Invoke(oTest, new object[] { 123 }); 33 } 34 { 35 MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(string) }); 36 method.Invoke(oTest, new object[] { "一生為你" }); 37 } 38 { 39 MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(int), typeof(string) }); 40 method.Invoke(oTest, new object[] { 234, "心欲無痕" }); 41 } 42 { 43 MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) }); 44 method.Invoke(oTest, new object[] { "PHS", 345 }); 45 } 46 { 47 MethodInfo method = type.GetMethod("Show5"); 48 method.Invoke(oTest, new object[] { "張中魁" });//靜態方法例項可以要 49 } 50 { 51 MethodInfo method = type.GetMethod("Show5"); 52 method.Invoke(null, new object[] { "張中魁" });//靜態方法例項也可以不要 53 }
反射呼叫私有方法
1 { 2 //呼叫私有方法 3 Console.WriteLine("&&&&&&&&&&&&&&&&&&&&私有方法&&&&&&&&&&&&&&&&&&&"); 4 Assembly assembly = Assembly.Load("SqlServerDb"); 5 Type type = assembly.GetType("SqlServerDb.ReflectionTest"); 6 object oTest = Activator.CreateInstance(type); 7 var method = type.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic); 8 method.Invoke(oTest, new object[] { "我是老王" }); 9 }
反射呼叫泛型方法
Assembly assembly = Assembly.Load("SqlServerDb"); Type type = assembly.GetType("SqlServerDb.GenericMethod"); object oGeneric = Activator.CreateInstance(type); foreach (var item in type.GetMethods()) { Console.WriteLine(item.Name); } MethodInfo method = type.GetMethod("Show"); //指定泛型方法的引數型別 var methodNew = method.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); object oReturn = methodNew.Invoke(oGeneric, new object[] { 123, "董小姐", DateTime.Now });
反射呼叫泛型方法加泛型類
1 Assembly assembly = Assembly.Load("SqlServerDb"); 2 //在獲取型別的同時通過MakeGenericType指定泛型的引數型別 3 Type type = assembly.GetType("SqlServerDb.GenericDouble`1").MakeGenericType(typeof(int)); 4 object oObject = Activator.CreateInstance(type); 5 MethodInfo method = type.GetMethod("Show").MakeGenericMethod(typeof(string), typeof(DateTime)); 6 method.Invoke(oObject, new object[] { 345, "感謝有夢", DateTime.Now });
&n