第六节:反射(几种写法、好处和弊端、利用反射实现IOC)
一. 加載dll,讀取相關(guān)信息
1. 加載程序集的三種方式
調(diào)用Assembly類下的三個(gè)方法:Load、LoadFile、LoadFrom。
1 //1.1 Load方法:動(dòng)態(tài)默認(rèn)加載當(dāng)前路徑下的(bin)下的dll文件,不需要后綴 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //1.2 LoadFile方法:程序集的絕對(duì)路徑 4 Assembly assembly2 = Assembly.LoadFile(@"D:\我的框架之路\DotNet體系\02-DotNet進(jìn)階\02-反射\01-code\Reflection\bin\Debug\DB.SQLServer.dll"); 5 //1.3 LoadFrom方法:可以是當(dāng)前路徑(需要寫上后綴.dll),也可以是絕對(duì)路徑 6 Assembly assembly3 = Assembly.LoadFrom("DB.SQLServer.dll");2. 獲取程序集中所有的類
通過方法GetTypes來實(shí)現(xiàn)。
1 Assembly assembly = Assembly.Load("DB.SQLServer"); 2 Type[] t1 = assembly.GetTypes();? ??通過方法GetType("類名全寫")來實(shí)現(xiàn)獲取單個(gè)類(DBHelper)。
1 Type tItem = assembly.GetType("DB.SQLServer.DBHelper");3. 獲取類中的所有構(gòu)造函數(shù)
?通過方法GetConstructors來實(shí)現(xiàn)。
1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2.獲取程序集中的特定類 4 Type tItem = assembly.GetType("DB.SQLServer.DBHelper"); 5 //3.獲取特定類中的所有構(gòu)造函數(shù) 6 ConstructorInfo[] cInfor = tItem.GetConstructors();4. 獲取類中的所有屬性
? 通過方法GetProperties來實(shí)現(xiàn)。
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來實(shí)現(xiàn)。
//1.加載程序集 Assembly assembly = Assembly.Load("DB.SQLServer"); //2.獲取程序集中的特定類 Type tItem = assembly.GetType("DB.SQLServer.DBHelper"); //3.獲取特定類中的所有方法 MethodInfo[] methordInfo = tItem.GetMethods();6. 獲取類中的所有接口
??通過方法GetInterfaces來實(shí)現(xiàn)。
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();二. 反射創(chuàng)建對(duì)象
1. 反射創(chuàng)建對(duì)象
通過Activator.CreateInstance()方法來創(chuàng)建對(duì)象
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 構(gòu)造函數(shù) 11 public ReflectionTest() 12 { 13 Console.WriteLine("這里是{0}無參數(shù)構(gòu)造函數(shù)", this.GetType()); 14 } 15 16 public ReflectionTest(string name) 17 { 18 Console.WriteLine("這里是{0} 有1個(gè)參數(shù)構(gòu)造函數(shù)", this.GetType()); 19 } 20 21 public ReflectionTest(int id, string name) 22 { 23 Console.WriteLine("這里是{0} 有2個(gè)參數(shù)構(gòu)造函數(shù)", 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 反射創(chuàng)建對(duì)象的代碼
1 //1.加載程序集2 Assembly assembly = Assembly.Load("DB.SQLServer");3 //2.獲取程序集中的特定類4 Type tItem = assembly.GetType("DB.SQLServer.ReflectionTest");5 //3.1 無參構(gòu)造函數(shù)6 Activator.CreateInstance(tItem);7 //3.2 一個(gè)參數(shù)的構(gòu)造函數(shù)8 Activator.CreateInstance(tItem ,"1");9 //3.3 兩個(gè)參數(shù)的構(gòu)造函數(shù) 10 Activator.CreateInstance(tItem , 1,"2");2. 反射破壞單例,調(diào)用私有構(gòu)造函數(shù)
? ?單例代碼
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 }? ?破壞單例,調(diào)用私有構(gòu)造函數(shù)代碼
1 //1.加載程序集 2 Assembly assembly = Assembly.Load("DB.SQLServer"); 3 //2. 獲取單例類 4 Type tc3 = assembly .GetType("DB.SQLServer.Singleton"); 5 //3. 創(chuàng)建對(duì)象 6 Activator.CreateInstance(tc3, true);3. 反射創(chuàng)建泛型(擴(kuò)展)
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(反射+簡(jiǎn)單工廠+配置文件)
? 背景:有三套相同的數(shù)據(jù)庫,分別是SQLServer、MySQL、Oracle數(shù)據(jù)庫,要求可以分別連接這三個(gè)不同的數(shù)據(jù)庫,并且發(fā)布后,可以在不重新發(fā)布的情況下,切換連接數(shù)據(jù)庫。
? 對(duì)應(yīng)上述背景,建立相應(yīng)的解決方案,目錄如下,并介紹介紹幾種傳統(tǒng)的解決方案
方案一:在Reflection中直接添加對(duì)DB.SQLServer的引用
1 Console.WriteLine("------------------------------------1. 傳統(tǒng)方式調(diào)用DBHelper中的Query方法--------------------------------------"); 2 //1.傳統(tǒng)的方式調(diào)用(需要對(duì) DB.SQLServer添加引用) 3 DBHelper db1 = new DBHelper("123"); 4 db1.Query();方案二:在Reflection中直接添加對(duì)DB.SQLServer、DB.Interface的引用
1 Console.WriteLine("------------------------------------2. 接口的方式調(diào)用--------------------------------------"); 2 //2. 接口的方式調(diào)用(只需要引用接口的程序集即可) 3 IDBHelper idb1 = new DBHelper("123"); 4 idb1.Query();點(diǎn)評(píng):以上兩種方案實(shí)質(zhì)上都是通過對(duì)相應(yīng)的實(shí)現(xiàn)類添加引用,new出來對(duì)象,然后調(diào)用方法來實(shí)現(xiàn),沒法發(fā)布后動(dòng)態(tài)修改數(shù)據(jù)庫。
?方案三:通過反射來創(chuàng)建對(duì)象,只需要添加對(duì)DB.Interface的引用即可,但需要把DB.SQLServer、DB.MySQL、DB.Oracle的生成dll的目錄改成Reflection程序下
1 Console.WriteLine("------------------------------------3. 反射的方式創(chuàng)建對(duì)象--------------------------------------"); 2 //3. 反射的方式創(chuàng)建對(duì)象(不需要直接添加對(duì)其引用,只需要把相應(yīng)的程序生成路徑改成Reflection中即可) 3 Assembly assembly4 = Assembly.Load("DB.SQLServer"); 4 Type tc = assembly4.GetType("DB.SQLServer.DBHelper"); 5 //object myDbHelper = Activator.CreateInstance(tc, "123"); //調(diào)用帶參數(shù)的構(gòu)造函數(shù) 6 object myDbHelper = Activator.CreateInstance(tc); //默認(rèn)調(diào)用無參構(gòu)造函數(shù) 7 IDBHelper idb2 = (IDBHelper)myDbHelper; 8 idb2.Query();點(diǎn)評(píng):該方案只需要對(duì)接口添加引用,符合了面向接口編程的思想,但是發(fā)布后在不修改代碼的情況下,不能切換數(shù)據(jù)庫。
方案四:IOC(反射+簡(jiǎn)單工廠+配置文件),需要添加對(duì)DB.Interface的引用,并且把DB.SQLServer、DB.MySQL、DB.Oracle的生成dll的目錄改成Reflection程序下
配置文件:
1 <appSettings>2 <!--直接修改配置文件,可以修改數(shù)據(jù)庫連接牛逼,可以直接切換 oracle 、mysql數(shù)據(jù)庫,發(fā)布后可以直接通過改配置文件,切換數(shù)據(jù)庫,代碼什么也不用改,體會(huì):反射+面向接口編程-->3 <!--前提:相應(yīng)的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>簡(jiǎn)單工廠:
1 /// <summary>2 /// 簡(jiǎn)單工廠,創(chuàng)建對(duì)象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 }調(diào)用:
1 Console.WriteLine("------------------------------------4. IOC(反射+簡(jiǎn)單工廠+配置文件)--------------------------------------"); 2 //4. IOC(反射+簡(jiǎn)單工廠+配置文件)(不需要直接添加對(duì)其引用,只需要把相應(yīng)的程序生成路徑改成Reflection中即可) 3 IDBHelper idb3 = SimpleFactory.CreateDBHelper(); 4 idb3.Query();?
?
四. 反射調(diào)用實(shí)例方法、靜態(tài)方法、重載方法
1 //2. 實(shí)例方法、靜態(tài)方法、重載方法的調(diào)用2 {3 object obj = Activator.CreateInstance(tc5);4 Console.WriteLine("---------------------------------2.1 調(diào)用無參、有參的實(shí)例方法-------------------------------------");5 //2.1 調(diào)用無參、有參的實(shí)例方法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 調(diào)用靜態(tài)方法-------------------------------------"); 16 //2.2 調(diào)用靜態(tài)方法 17 { 18 MethodInfo methord = tc5.GetMethod("ShowStatic"); 19 methord.Invoke(obj, new object[] { "ShowStatic1234" }); 20 } 21 22 Console.WriteLine("---------------------------------2.3 調(diào)用重載方法(需要在創(chuàng)建方法的時(shí)候,把類型傳進(jìn)去)-------------------------------------"); 23 //2.3 調(diào)用重載方法(需要在創(chuàng)建方法的時(shí)候,把類型傳進(jìn)去) 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 調(diào)用私有方法-------------------------------------"); 46 //2.4 調(diào)用私有方法 47 { 48 MethodInfo methord = tc5.GetMethod("Show4", BindingFlags.Instance|BindingFlags.NonPublic); 49 methord.Invoke(obj, new object[] { "11" }); 50 } 51 Console.WriteLine("---------------------------------2.5 調(diào)用泛型方法-------------------------------------"); 52 //2.5 調(diào)用泛型方法 53 { 54 MethodInfo methord = tc5.GetMethod("ShowGeneric"); 55 methord = methord.MakeGenericMethod(typeof(string)); 56 methord.Invoke(obj, new object[] { "123" }); 57 } 58 59 }五. 反射字段和屬性,獲取值和設(shè)置值
{//實(shí)例化對(duì)象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中的重要機(jī)制,通過反射,可以在運(yùn)行時(shí)獲得程序或程序集中每一個(gè)類型(包括類、結(jié)構(gòu)、委托、接口和枚舉等)的成員和成員的信息。4 //有了反射,即可對(duì)每一個(gè)類型了如指掌。另外我還可以直接創(chuàng)建對(duì)象,即使這個(gè)對(duì)象的類型在編譯時(shí)還不知道。5 6 //性能局限7 Console.WriteLine("------------------------------測(cè)試普通方法和反射的耗時(shí)情況--------------------------------------");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("普通方式花費(fèi){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("反射方式花費(fèi){0}ms:", watch.ElapsedMilliseconds); 47 } 48 }運(yùn)行結(jié)果:
?七. 補(bǔ)充:獲取類的屬性、方法、特性、構(gòu)造函數(shù)等,設(shè)置屬性值,獲取屬性值
函數(shù) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 說明
GetConstructor(s) ? ? ? ? ? ? ? ? ?取得此類型的創(chuàng)建函數(shù),其將回傳一個(gè)ConstructorInfo對(duì)象或數(shù)組
GetField(s) ? ? ? ? ? ? ? ? ? ? ? ? ? ? 取得此類型中成員變量,其將回傳一個(gè)FiledInfo對(duì)象或數(shù)組
GetMember(s) ? ? ? ? ? ? ? ? ? ? ? ?取得此類中的成員,其類型可以是變量、事件、屬性、方法及Nested Type,其將回傳一個(gè)MemberInfo對(duì)象或數(shù)組
GetEvent(s) ? ? ? ? ? ? ? ? ? ? ? ? ? ?取得此類型中的事件,其將回傳一個(gè)EventInfo對(duì)象或數(shù)組
GetProperty/GetProperties ? ? ? ? 取得此類型中的屬性,其將回傳一個(gè)PropertyInfo對(duì)象或數(shù)組
GetNestedType(s) ? ? ? ? ? ? ? ? ?取得聲明于此類型內(nèi)類型,其將回傳一個(gè)Type對(duì)象或數(shù)組
GetCustomAttibutes ? ? ? ? ? ? ? ? ? ?取得綁定于此類型的Attitudes
GetValue(t) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?獲取t對(duì)象的的屬性值
SetValue(t,"XXX") ? ? ? ? ? ? ? ? ? ? ? ?設(shè)置t對(duì)象的屬性值為XXX
實(shí)體代碼:
1 [Description("我是Person類")]2 public class Person3 {4 //1. 構(gòu)造函數(shù)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 }調(diào)用代碼:
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. 獲取構(gòu)造函數(shù)-----------------"); 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 //因?yàn)檫@些測(cè)試所用的特性都是加在屬性上的,所以要先獲取屬性 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 //設(shè)置屬性值 77 idProperty.SetValue(person1, "2345"); 78 Console.WriteLine("設(shè)置后的屬性值為:{0}", idProperty.GetValue(person1)); 79 80 }結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的第六节:反射(几种写法、好处和弊端、利用反射实现IOC)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《街头霸王6》全新实机演示公布:春丽身材
- 下一篇: 明星贾乃亮合伙公司偷逃税被罚 被曝隐匿2