日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第六节:反射(几种写法、好处和弊端、利用反射实现IOC)

發布時間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第六节:反射(几种写法、好处和弊端、利用反射实现IOC) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一. 加載dll,讀取相關信息

1. 加載程序集的三種方式

 調用Assembly類下的三個方法:Load、LoadFile、LoadFrom。

1       //1.1 Load方法:動態默認加載當前路徑下的(bin)下的dll文件,不需要后綴 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //1.2 LoadFile方法:程序集的絕對路徑 4 Assembly assembly2 = Assembly.LoadFile(@"D:\我的框架之路\DotNet體系\02-DotNet進階\02-反射\01-code\Reflection\bin\Debug\DB.SQLServer.dll"); 5 //1.3 LoadFrom方法:可以是當前路徑(需要寫上后綴.dll),也可以是絕對路徑 6 Assembly assembly3 = Assembly.LoadFrom("DB.SQLServer.dll");

2. 獲取程序集中所有的類

 通過方法GetTypes來實現。

1 Assembly assembly = Assembly.Load("DB.SQLServer"); 2 Type[] t1 = assembly.GetTypes();

? ??通過方法GetType("類名全寫")來實現獲取單個類(DBHelper)。

1 Type tItem = assembly.GetType("DB.SQLServer.DBHelper");

3. 獲取類中的所有構造函數

 ?通過方法GetConstructors來實現。

1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2.獲取程序集中的特定類 4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper"); 5 //3.獲取特定類中的所有構造函數 6 ConstructorInfo[] cInfor = tItem.GetConstructors();

4. 獲取類中的所有屬性

? 通過方法GetProperties來實現。

1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2.獲取程序集中的特定類 4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper"); 5 //3.獲取特定類中的所有屬性 6 PropertyInfo[] propertyInfo = tItem.GetProperties();

5. 獲取類中的所有方法

???通過方法GetMethods來實現。

//1.加載程序集 Assembly assembly = Assembly.Load("DB.SQLServer"); //2.獲取程序集中的特定類 Type tItem = assembly.GetType("DB.SQLServer.DBHelper"); //3.獲取特定類中的所有方法 MethodInfo[] methordInfo = tItem.GetMethods();

6. 獲取類中的所有接口

??通過方法GetInterfaces來實現。

1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2.獲取程序集中的特定類 4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper"); 5 //3.獲取特定類中的所有接口 6 Type[] type = tItem.GetInterfaces();

二. 反射創建對象

1. 反射創建對象

 通過Activator.CreateInstance()方法來創建對象

1.1 ReflectionTest類的代碼

1 public class ReflectionTest2 {3 public int Id { get; set; }4 public string Name { get; set; }5 6 public string Field = null;7 public static string FieldStatic = null;8 9 10 #region 構造函數 11 public ReflectionTest() 12 { 13 Console.WriteLine("這里是{0}無參數構造函數", this.GetType()); 14 } 15 16 public ReflectionTest(string name) 17 { 18 Console.WriteLine("這里是{0} 有1個參數構造函數", this.GetType()); 19 } 20 21 public ReflectionTest(int id, string name) 22 { 23 Console.WriteLine("這里是{0} 有2個參數構造函數", this.GetType()); 24 } 25 #endregion 26 27 public void Show1() 28 { 29 Console.WriteLine("這里是{0}的Show1", this.GetType()); 30 } 31 32 public void Show2(int id) 33 { 34 35 Console.WriteLine("這里是{0}的Show2", this.GetType()); 36 } 37 38 public static void ShowStatic(string name) 39 { 40 Console.WriteLine("這里是{0}的ShowStatic", typeof(ReflectionTest)); 41 } 42 43 public void Show3() 44 { 45 Console.WriteLine("這里是{0}的Show3_1", this.GetType()); 46 } 47 48 public void Show3(int id, string name) 49 { 50 Console.WriteLine("這里是{0}的Show3", this.GetType()); 51 } 52 53 public void Show3(string name, int id) 54 { 55 Console.WriteLine("這里是{0}的Show3_2", this.GetType()); 56 } 57 58 public void Show3(int id) 59 { 60 61 Console.WriteLine("這里是{0}的Show3_3", this.GetType()); 62 } 63 64 public void Show3(string name) 65 { 66 67 Console.WriteLine("這里是{0}的Show3_4", this.GetType()); 68 } 69 70 private void Show4(string name) 71 { 72 Console.WriteLine("這里是{0}的Show4", this.GetType()); 73 } 74 public void ShowGeneric<T>(T name) 75 { 76 Console.WriteLine("這里是{0}的ShowStatic T={1}", this.GetType(), typeof(T)); 77 } 78 }

1.2 反射創建對象的代碼

1 //1.加載程序集2 Assembly assembly = Assembly.Load("DB.SQLServer");3 //2.獲取程序集中的特定類4 Type tItem = assembly.GetType("DB.SQLServer.ReflectionTest");5 //3.1 無參構造函數6 Activator.CreateInstance(tItem);7 //3.2 一個參數的構造函數8 Activator.CreateInstance(tItem ,"1");9 //3.3 兩個參數的構造函數 10 Activator.CreateInstance(tItem , 1,"2");

2. 反射破壞單例,調用私有構造函數

? ?單例代碼

1 public sealed class Singleton2 {3 private Singleton()4 {5 Console.WriteLine("初始化一次");6 }7 8 private static Singleton Instance = new Singleton();9 10 public static Singleton CreateInstance() 11 { 12 return Instance; 13 } 14 }

? ?破壞單例,調用私有構造函數代碼

1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2. 獲取單例類 4 Type tc3 = assembly .GetType("DB.SQLServer.Singleton"); 5 //3. 創建對象 6 Activator.CreateInstance(tc3, true);

3. 反射創建泛型(擴展)

1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2. 獲取單例類 4 Type tc4 = assembly4.GetType("DB.SQLServer.GenericClass`1"); 5 tc4 = tc4.MakeGenericType(typeof(int)); 6 Activator.CreateInstance(tc4);

三.?IOC(反射+簡單工廠+配置文件)

?  背景:有三套相同的數據庫,分別是SQLServer、MySQL、Oracle數據庫,要求可以分別連接這三個不同的數據庫,并且發布后,可以在不重新發布的情況下,切換連接數據庫。

?  對應上述背景,建立相應的解決方案,目錄如下,并介紹介紹幾種傳統的解決方案

方案一:在Reflection中直接添加對DB.SQLServer的引用

1 Console.WriteLine("------------------------------------1. 傳統方式調用DBHelper中的Query方法--------------------------------------"); 2 //1.傳統的方式調用(需要對 DB.SQLServer添加引用) 3 DBHelper db1 = new DBHelper("123"); 4 db1.Query();

方案二:在Reflection中直接添加對DB.SQLServer、DB.Interface的引用

1 Console.WriteLine("------------------------------------2. 接口的方式調用--------------------------------------"); 2 //2. 接口的方式調用(只需要引用接口的程序集即可) 3 IDBHelper idb1 = new DBHelper("123"); 4 idb1.Query();

點評:以上兩種方案實質上都是通過對相應的實現類添加引用,new出來對象,然后調用方法來實現,沒法發布后動態修改數據庫。

?方案三:通過反射來創建對象,只需要添加對DB.Interface的引用即可,但需要把DB.SQLServer、DB.MySQL、DB.Oracle的生成dll的目錄改成Reflection程序下

1 Console.WriteLine("------------------------------------3. 反射的方式創建對象--------------------------------------"); 2 //3. 反射的方式創建對象(不需要直接添加對其引用,只需要把相應的程序生成路徑改成Reflection中即可) 3 Assembly assembly4 = Assembly.Load("DB.SQLServer"); 4 Type tc = assembly4.GetType("DB.SQLServer.DBHelper"); 5 //object myDbHelper = Activator.CreateInstance(tc, "123"); //調用帶參數的構造函數 6 object myDbHelper = Activator.CreateInstance(tc); //默認調用無參構造函數 7 IDBHelper idb2 = (IDBHelper)myDbHelper; 8 idb2.Query();

點評:該方案只需要對接口添加引用,符合了面向接口編程的思想,但是發布后在不修改代碼的情況下,不能切換數據庫。

方案四:IOC(反射+簡單工廠+配置文件),需要添加對DB.Interface的引用,并且把DB.SQLServer、DB.MySQL、DB.Oracle的生成dll的目錄改成Reflection程序下

配置文件:

1 <appSettings>2 <!--直接修改配置文件,可以修改數據庫連接牛逼,可以直接切換 oracle 、mysql數據庫,發布后可以直接通過改配置文件,切換數據庫,代碼什么也不用改,體會:反射+面向接口編程-->3 <!--前提:相應的DBHelper類必須滿足接口約束,需要把Oracle或MySql的dll文件拷貝到Reflection中的bin文件中 -->4 <!--SQLServer改為: -->5 <!--<add key="IDBHelper-dllName" value="DB.SQLServer"/>6 <add key="IDBHelper-className" value="DB.SQLServer.DBHelper"/>-->7 <!--Oracle改為: -->8 <!--<add key="IDBHelper-dllName" value="DB.Oracle"/>9 <add key="IDBHelper-className" value="DB.Oracle.DBHelper"/>--> 10 <!--MySql改為: --> 11 <add key="IDBHelper-dllName" value="DB.MySql"/> 12 <add key="IDBHelper-className" value="DB.MySql.DBHelper"/> 13 </appSettings>

簡單工廠:

1 /// <summary>2 /// 簡單工廠,創建對象3 /// </summary>4 public class SimpleFactory5 {6 private static string IDBHelperdllName = ConfigurationManager.AppSettings["IDBHelper-dllName"];7 private static string IDBHelperClassName = ConfigurationManager.AppSettings["IDBHelper-className"];8 9 public static IDBHelper CreateDBHelper() 10 { 11 Assembly assembly = Assembly.Load(IDBHelperdllName); 12 Type type = assembly.GetType(IDBHelperClassName); 13 object obj = Activator.CreateInstance(type); 14 return (IDBHelper)obj; 15 } 16 17 }

調用:

1 Console.WriteLine("------------------------------------4. IOC(反射+簡單工廠+配置文件)--------------------------------------"); 2 //4. IOC(反射+簡單工廠+配置文件)(不需要直接添加對其引用,只需要把相應的程序生成路徑改成Reflection中即可) 3 IDBHelper idb3 = SimpleFactory.CreateDBHelper(); 4 idb3.Query();

?

?

四. 反射調用實例方法、靜態方法、重載方法

1       //2. 實例方法、靜態方法、重載方法的調用2 {3 object obj = Activator.CreateInstance(tc5);4 Console.WriteLine("---------------------------------2.1 調用無參、有參的實例方法-------------------------------------");5 //2.1 調用無參、有參的實例方法6 {7 MethodInfo methord = tc5.GetMethod("Show1");8 methord.Invoke(obj, null);9 } 10 { 11 MethodInfo methord = tc5.GetMethod("Show2"); 12 methord.Invoke(obj, new object[]{11}); 13 } 14 15 Console.WriteLine("---------------------------------2.2 調用靜態方法-------------------------------------"); 16 //2.2 調用靜態方法 17 { 18 MethodInfo methord = tc5.GetMethod("ShowStatic"); 19 methord.Invoke(obj, new object[] { "ShowStatic1234" }); 20 } 21 22 Console.WriteLine("---------------------------------2.3 調用重載方法(需要在創建方法的時候,把類型傳進去)-------------------------------------"); 23 //2.3 調用重載方法(需要在創建方法的時候,把類型傳進去) 24 { 25 MethodInfo methord = tc5.GetMethod("Show3", new Type[] { }); 26 methord.Invoke(obj, null); 27 } 28 { 29 MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(int)}); 30 methord.Invoke(obj, new object[] { 11 }); 31 } 32 { 33 MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(string) }); 34 methord.Invoke(obj, new object[] { "11" }); 35 } 36 { 37 MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(int), typeof(string) }); 38 methord.Invoke(obj, new object[] { 11 ,"11"}); 39 } 40 { 41 MethodInfo methord = tc5.GetMethod("Show3", new Type[] { typeof(string), typeof(int) }); 42 methord.Invoke(obj, new object[] { "11",11 }); 43 } 44 45 Console.WriteLine("---------------------------------2.4 調用私有方法-------------------------------------"); 46 //2.4 調用私有方法 47 { 48 MethodInfo methord = tc5.GetMethod("Show4", BindingFlags.Instance|BindingFlags.NonPublic); 49 methord.Invoke(obj, new object[] { "11" }); 50 } 51 Console.WriteLine("---------------------------------2.5 調用泛型方法-------------------------------------"); 52 //2.5 調用泛型方法 53 { 54 MethodInfo methord = tc5.GetMethod("ShowGeneric"); 55 methord = methord.MakeGenericMethod(typeof(string)); 56 methord.Invoke(obj, new object[] { "123" }); 57 } 58 59 }

五. 反射字段和屬性,獲取值和設置值

{//實例化對象ReflectionTest rTest = new ReflectionTest();//反射Assembly assembly5 = Assembly.Load("DB.SQLServer");Type type5 = assembly5.GetType("DB.SQLServer.ReflectionTest");object object5 = Activator.CreateInstance(type5);//1.獲取類的所有屬性Console.WriteLine("------------------------------------1.獲取類的屬性--------------------------------------");var pInfor= type5.GetProperties();foreach (var item in pInfor){Console.WriteLine(item.Name);if (item.Name.Equals("Id")){item.SetValue(object5, 12332);}}Console.WriteLine("------------------------------------輸出ID屬性值--------------------------------------");rTest = (ReflectionTest)object5;Console.WriteLine(rTest.Id);//2.獲取類的字段Console.WriteLine("------------------------------------2.獲取類的字段--------------------------------------");foreach (var item in type5.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)){Console.WriteLine(item.Name);}}

六. 反射的好處和局限

1 {2 //反射的好處:3 //反射是.NET中的重要機制,通過反射,可以在運行時獲得程序或程序集中每一個類型(包括類、結構、委托、接口和枚舉等)的成員和成員的信息。4 //有了反射,即可對每一個類型了如指掌。另外我還可以直接創建對象,即使這個對象的類型在編譯時還不知道。5 6 //性能局限7 Console.WriteLine("------------------------------測試普通方法和反射的耗時情況--------------------------------------");8 {9 //1.普通方法 10 Stopwatch watch = new Stopwatch(); 11 watch.Start(); 12 for (var i = 0; i < 1000000; i++) 13 { 14 DBHelper2 dh = new DBHelper2(); 15 dh.Id = 1; 16 dh.Name = "maru"; 17 dh.Query(); 18 } 19 watch.Stop(); 20 Console.WriteLine("普通方式花費{0}ms:",watch.ElapsedMilliseconds); 21 } 22 { 23 //2. 反射的方法 24 Stopwatch watch = new Stopwatch(); 25 watch.Start(); 26 Assembly assembley6 = Assembly.Load("DB.SQLServer"); 27 Type type6 = assembley6.GetType("DB.SQLServer.DBHelper2"); 28 for (var i = 0; i < 1000000; i++) 29 { 30 object obj6 = Activator.CreateInstance(type6); 31 foreach (var item in type6.GetProperties()) 32 { 33 if (item.Name.Equals("Id")) 34 { 35 item.SetValue(obj6, 1); 36 } 37 if (item.Name.Equals("Name")) 38 { 39 item.SetValue(obj6, "maru"); 40 } 41 } 42 MethodInfo m6 = type6.GetMethod("Query"); 43 m6.Invoke(obj6, null); 44 } 45 watch.Stop(); 46 Console.WriteLine("反射方式花費{0}ms:", watch.ElapsedMilliseconds); 47 } 48 }

運行結果:

?七. 補充:獲取類的屬性、方法、特性、構造函數等,設置屬性值,獲取屬性值

函數 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 說明
GetConstructor(s) ? ? ? ? ? ? ? ? ?取得此類型的創建函數,其將回傳一個ConstructorInfo對象或數組
GetField(s) ? ? ? ? ? ? ? ? ? ? ? ? ? ? 取得此類型中成員變量,其將回傳一個FiledInfo對象或數組
GetMember(s) ? ? ? ? ? ? ? ? ? ? ? ?取得此類中的成員,其類型可以是變量、事件、屬性、方法及Nested Type,其將回傳一個MemberInfo對象或數組
GetEvent(s) ? ? ? ? ? ? ? ? ? ? ? ? ? ?取得此類型中的事件,其將回傳一個EventInfo對象或數組
GetProperty/GetProperties ? ? ? ? 取得此類型中的屬性,其將回傳一個PropertyInfo對象或數組
GetNestedType(s) ? ? ? ? ? ? ? ? ?取得聲明于此類型內類型,其將回傳一個Type對象或數組
GetCustomAttibutes ? ? ? ? ? ? ? ? ? ?取得綁定于此類型的Attitudes
GetValue(t) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?獲取t對象的的屬性值
SetValue(t,"XXX") ? ? ? ? ? ? ? ? ? ? ? ?設置t對象的屬性值為XXX

實體代碼:

1 [Description("我是Person類")]2 public class Person3 {4 //1. 構造函數5 public Person()6 {7 8 }9 public Person(string sex) 10 { 11 this._Sex = sex; 12 } 13 //2. 屬性 14 15 [Description("我是id")] 16 public string id { get; set; } 17 18 [ReadOnly(true)] 19 public string userName { get; set; } 20 21 public string userPwd { get; set; } 22 23 //3.成員變量 24 25 public string _Sex = null; 26 27 public int _Age; 28 29 //4. 特性 [Description("我是id")] [ReadOnly(true)] 30 31 //5. 方法 32 public string GetOwnSex() 33 { 34 return this._Sex; 35 } 36 37 //6. 事件 38 public event Action MyEvent; 39 40 41 42 }

調用代碼:

1 Person person1 = new Person()2 {3 id = "123",4 userName = "ypf",5 userPwd = "123456",6 };7 //獲取類8 Type type = person1.GetType();9 { 10 Console.WriteLine("---------------1. 獲取構造函數-----------------"); 11 ConstructorInfo[] constructorInfoList = type.GetConstructors(); 12 for (int i = 0; i < constructorInfoList.Length; i++) 13 { 14 Console.WriteLine(constructorInfoList[i]); 15 } 16 } 17 { 18 Console.WriteLine("---------------2. 獲取成員變量-----------------"); 19 FieldInfo[] fielInforList = type.GetFields(); 20 for (int i = 0; i < fielInforList.Length; i++) 21 { 22 Console.WriteLine(fielInforList[i]); 23 } 24 } 25 { 26 Console.WriteLine("---------------3. 獲取成員-----------------"); 27 MemberInfo[] memberInfoList = type.GetMembers(); 28 for (int i = 0; i < memberInfoList.Length; i++) 29 { 30 Console.WriteLine(memberInfoList[i]); 31 } 32 } 33 { 34 Console.WriteLine("---------------4. 獲取事件-----------------"); 35 EventInfo[] eventInfoList = type.GetEvents(); 36 for (int i = 0; i < eventInfoList.Length; i++) 37 { 38 Console.WriteLine(eventInfoList[i]); 39 } 40 } 41 { 42 Console.WriteLine("---------------5. 獲取屬性-----------------"); 43 PropertyInfo[] propertyInfoList = type.GetProperties(); 44 for (int i = 0; i < propertyInfoList.Length; i++) 45 { 46 Console.WriteLine(propertyInfoList[i]); 47 } 48 } 49 { 50 Console.WriteLine("---------------6. 獲取特性-----------------"); 51 //1. 獲取屬性上的特性 52 //因為這些測試所用的特性都是加在屬性上的,所以要先獲取屬性 53 PropertyInfo[] propertyInfoList = type.GetProperties(); 54 foreach (var item in propertyInfoList) 55 { 56 //獲取該屬性上的所有特性 57 object[] attributeInfoList = item.GetCustomAttributes(true); 58 foreach (var item2 in attributeInfoList) 59 { 60 Console.WriteLine("{0}屬性上的特性為{1}", item, item2); 61 } 62 63 } 64 //2. 獲取類上的屬性 65 object[] attributeInfoList2 = type.GetCustomAttributes(true); 66 foreach (var item3 in attributeInfoList2) 67 { 68 Console.WriteLine("{0}類上的特性為{1}", type, item3); 69 } 70 } 71 { 72 Console.WriteLine("---------------7. 獲取id屬性的值-----------------"); 73 PropertyInfo idProperty = type.GetProperty("id"); 74 Console.WriteLine("屬性名為:{0}", idProperty.Name); 75 Console.WriteLine("屬性值為:{0}", idProperty.GetValue(person1)); 76 //設置屬性值 77 idProperty.SetValue(person1, "2345"); 78 Console.WriteLine("設置后的屬性值為:{0}", idProperty.GetValue(person1)); 79 80 }

結果:

總結

以上是生活随笔為你收集整理的第六节:反射(几种写法、好处和弊端、利用反射实现IOC)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。