一. 加载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 }
结果: