反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。
反射的用途为提升应用程序的灵活性,扩展性。在运行时读取对象,设置对象,调用对象。
- dll - IL - metadata 反射
- 反射加载dll,读取module,类,方法,特性
- 反射创建对象,反射+简单工厂+配置文件 破坏单例,创建泛型
- 反射调用实例方法,静态方法,重载方法 调用私有方法,泛型方法
- 反射字段和属性,分别获取值和设置值
1,通过图例来说明程序的运行过程,以及反射调用的内容来自运行过程的哪一个环节。
反射调用的是代码通过编译器编译之后的生成的dll中的元数据。这些元数据包括:应用程序集的描述,应用程序集中的模块,构造函数,方法,字段,事件,属性,参数信息。
通过反射得到相应的元数据元素,可以对其:创建对象,调用,设置值。
2,反射加载dll,读取模块,类,方法,特性
反射用到的命名空间有:System.Reflection 和 System.Type
通过System.Reflection中的Assembly.Load("dll名称不要后缀")来加载dll返回一个Assembly的对象,再通过返回的Assembly对象中的GetType("dll名称+类名")返回一个对象,通过这个返回的对象来调用,设置该类中方法,属性,事件等等。
eg: Assembly assembly = Assembly.Load("Reflection.DB.MySql");
Type type = assembly.GetType("Reflection.DB.MySql.MySqlHelper");
1 { 2 Console.WriteLine("***************Reflection反射调用******************"); 3 Assembly assembly = Assembly.Load("Reflection.DB.MySql"); 4 foreach (var item in assembly.GetModules()) 5 { 6 Console.WriteLine(item.Name); 7 } 8 9 foreach (var item in assembly.GetTypes()) //获取所有的类 10 { 11 Console.WriteLine(item.Name); 12 } 13 14 Type type = assembly.GetType("Reflection.DB.MySql.MySqlHelper"); 15 object objHelper = Activator.CreateInstance(type); //调用了构造函数 16 IDBHelper dbHelper = objHelper as IDBHelper; //将objHelper转换为接口IDBHelper 17 dbHelper.Query(); 18 }
3.1,反射创建对象,反射+简单工厂+配置文件
通过把以上的代码进行整理,抽取,用配置文件和简单工厂的方法来返回对象。
<appSettings> <add key="SqlHelperConfig" value="Reflection.DB.Oracle,Reflection.DB.Oracle.OracleHelper"/> </appSettings>
再通过简单工厂来调用。
1 public class SimpleFactory 2 { 3 //第2步简单工厂 4 //静态字段读取配置文件中的内容 5 private static string IDBHelperString = ConfigurationManager.AppSettings["SqlHelperConfig"]; 6 private static string DllName = IDBHelperString.Split(',')[0]; //获取dll名称 7 private static string ClassName = IDBHelperString.Split(',')[1]; //获取类型名称 8 9 public static IDBHelper CreateInstance() 10 { 11 Assembly assembly = Assembly.Load(DllName); 12 Type type = assembly.GetType(ClassName); 13 object objHelper = Activator.CreateInstance(type); 14 return objHelper as IDBHelper; 15 } 16 }
这样做会增加应用程序的灵活性,比如现阶段应用程序使用的是MySql数据库需要换成oracle数据库。这样只需要再做一个类库去实现oracle的数据库操作改变配置文件中的dll和相应类库的名称即可。
3.2 破坏单例 创建泛型
1 /// <summary> 2 /// 单例模式,保证进程中始终只有一个对象 3 /// </summary> 4 public sealed class Singleton 5 { 6 private static Singleton _Singleton = null; 7 private Singleton() 8 { 9 Console.WriteLine("Singleton被构造"); 10 } 11 12 static Singleton() 13 { 14 _Singleton = new Singleton(); 15 } 16 17 public static Singleton GetInstance() 18 { 19 return _Singleton; 20 } 21 }
{ Console.WriteLine("*************** 多构造函数,破坏单例,创建泛型 ******************"); //第三步,调用多构造函数 Assembly assembly = Assembly.Load("Reflection.DB.SqlServer"); //加载dll Type type = assembly.GetType("Reflection.DB.SqlServer.Methods"); //加载类 foreach (var item in type.GetConstructors()) { //打印所有的构造函数 Console.WriteLine(item.Name); } //调用构造函数 Activator.CreateInstance(type);//调用默认的构造函数 Activator.CreateInstance(type, new object[] { 123 }); Activator.CreateInstance(type, new object[] { "ABC" }); //反射调用私有构造方法,破坏单例,多次构造对象,调用私有的构造函数 //单例:保证一个对象在进程中只有一个,并且只被构建一次 Type singletonType = assembly.GetType("Reflection.DB.SqlServer.Singleton"); object objSingleton1 = Activator.CreateInstance(singletonType, true); object objSingleton2 = Activator.CreateInstance(singletonType, true); object objSingleton3 = Activator.CreateInstance(singletonType, true); object objSingleton4 = Activator.CreateInstance(singletonType, true); //创建泛型 Type genericType = assembly.GetType("Reflection.DB.SqlServer.GenericClass`3"); //泛型类有三个泛型参数 Type genericNewType = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); object objGeneric = Activator.CreateInstance(genericNewType); }
4,反射调用实例方法,静态方法,重载方法
1 /// <summary> 2 /// 反射测试类 3 /// </summary> 4 public class Methods 5 { 6 #region Identity 7 /// <summary> 8 /// 无参构造函数 9 /// </summary> 10 public Methods() 11 { 12 Console.WriteLine("这里是{0}无参数构造函数", this.GetType()); 13 } 14 15 /// <summary> 16 /// 带参数构造函数 17 /// </summary> 18 /// <param name="name"></param> 19 public Methods(string name) 20 { 21 Console.WriteLine("这里是{0} 有参数构造函数", this.GetType()); 22 } 23 24 public Methods(int id) 25 { 26 Console.WriteLine("这里是{0} 有参数构造函数", this.GetType()); 27 } 28 #endregion 29 30 #region Method 31 /// <summary> 32 /// 无参方法 33 /// </summary> 34 public void Show1() 35 { 36 Console.WriteLine("这里是{0}的Show1", this.GetType()); 37 } 38 /// <summary> 39 /// 有参数方法 40 /// </summary> 41 /// <param name="id"></param> 42 public void Show2(int id) 43 { 44 45 Console.WriteLine("这里是{0}的Show2", this.GetType()); 46 } 47 /// <summary> 48 /// 重载方法之一 49 /// </summary> 50 /// <param name="id"></param> 51 /// <param name="name"></param> 52 public void Show3(int id, string name) 53 { 54 Console.WriteLine("这里是{0}的Show3", this.GetType()); 55 } 56 /// <summary> 57 /// 重载方法之二 58 /// </summary> 59 /// <param name="name"></param> 60 /// <param name="id"></param> 61 public void Show3(string name, int id) 62 { 63 Console.WriteLine("这里是{0}的Show3_2", this.GetType()); 64 } 65 /// <summary> 66 /// 重载方法之三 67 /// </summary> 68 /// <param name="id"></param> 69 public void Show3(int id) 70 { 71 72 Console.WriteLine("这里是{0}的Show3_3", this.GetType()); 73 } 74 /// <summary> 75 /// 重载方法之四 76 /// </summary> 77 /// <param name="name"></param> 78 public void Show3(string name) 79 { 80 81 Console.WriteLine("这里是{0}的Show3_4", this.GetType()); 82 } 83 /// <summary> 84 /// 重载方法之五 85 /// </summary> 86 public void Show3() 87 { 88 89 Console.WriteLine("这里是{0}的Show3_1", this.GetType()); 90 } 91 /// <summary> 92 /// 私有方法 93 /// </summary> 94 /// <param name="name"></param> 95 private void Show4(string name) 96 { 97 Console.WriteLine("这里是{0}的Show4", this.GetType()); 98 } 99 /// <summary> 100 /// 静态方法 101 /// </summary> 102 /// <param name="name"></param> 103 public static void Show5(string name) 104 { 105 Console.WriteLine("这里是{0}的Show5", typeof(Methods)); 106 } 107 #endregion 108 } 109 110 public class GenericClass<T, W, X> 111 { 112 public void Show(T t, W w, X x) 113 { 114 Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name); 115 } 116 } 117 118 public class GenericMethod 119 { 120 public void Show<T, W, X>(T t, W w, X x) 121 { 122 Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name); 123 } 124 } 125 126 public class GenericDouble<T> 127 { 128 public void Show<W, X>(T t, W w, X x) 129 { 130 Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name); 131 } 132 }
1 #region 反射调用实例方法,静态方法,重载方法 2 { 3 Console.WriteLine("*************** 反射调用实例方法,静态方法,重载方法 ******************"); 4 //第三步,调用多构造函数 5 Assembly assembly = Assembly.Load("Reflection.DB.SqlServer"); //加载dll 6 Type type = assembly.GetType("Reflection.DB.SqlServer.Methods"); //加载类 7 foreach (var item in type.GetMethods()) 8 { //打印所有的构造函数 9 Console.WriteLine(item.Name); 10 } 11 12 //调用构造函数,创建实例 13 object obj = Activator.CreateInstance(type); 14 { 15 //调用无参数的实例方法 16 MethodInfo methodinfo = type.GetMethod("Show1"); 17 methodinfo.Invoke(obj, null); 18 } 19 { 20 //调用有参数的静态方法 21 MethodInfo methodinfo = type.GetMethod("Show5"); 22 //调用静态方法,对其调用方法或构造函数的对象可以传递也可以忽略 23 methodinfo.Invoke(obj, new object[] { "静态方法的参数1"}); 24 methodinfo.Invoke(null, new object[] { "静态方法的参数2" }); 25 } 26 { 27 //调用有参数的重载方法 1 ,参数为int 28 MethodInfo methodinfo = type.GetMethod("Show3",new Type[] {typeof(int)}); 29 methodinfo.Invoke(obj, new object[] { 1 }); 30 } 31 32 { 33 //调用有参数的重载方法 2 , 参数为string 34 MethodInfo methodinfo = type.GetMethod("Show3",new Type[] { typeof(string)}); 35 methodinfo.Invoke(obj, new object[] { "string类型重载方法" }); 36 } 37 38 { 39 //调用有参数的重载方法 3 , 参数为int , string 40 MethodInfo methodinfo = type.GetMethod("Show3", new Type[] { typeof(int),typeof(string) }); 41 methodinfo.Invoke(obj, new object[] { 1,"string类型重载方法" }); 42 } 43 44 { 45 //调用有参数的重载方法 4 , 参数为string , int 46 MethodInfo methodinfo = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int)}); 47 methodinfo.Invoke(obj, new object[] { "string类型重载方法",1 }); 48 } 49 } 50 #endregion
4.2 反射调用私有方法,泛型方法
需要注意调用私有方法时候需要在type.GetMethod("MethodName",BindingFlag.Instance | BindingFlag.NonPublic);
另外需要注意在调用泛型类中的泛型方法和普通类中的泛型方法这两者的区别。
1 #region 反射调用私有方法,泛型方法 2 { 3 Console.WriteLine("*************** 反射调用私有方法,泛型方法 ******************"); 4 //第三步,调用多构造函数 5 Assembly assembly = Assembly.Load("Reflection.DB.SqlServer"); //加载dll 6 Type type = assembly.GetType("Reflection.DB.SqlServer.Methods"); //加载类 7 8 //调用构造函数,创建实例 9 object obj = Activator.CreateInstance(type); 10 { 11 MethodInfo methodinfo = type.GetMethod("Show4",BindingFlags.Instance | BindingFlags.NonPublic); 12 methodinfo.Invoke(obj, new object[] { "aaa" }); 13 } 14 { 15 //调用普通类中的泛型方法 16 Type genericType = assembly.GetType("Reflection.DB.SqlServer.GenericMethod"); 17 object genericObj = Activator.CreateInstance(genericType); 18 MethodInfo method = genericType.GetMethod("Show"); 19 MethodInfo methodNew = method.MakeGenericMethod(new Type[] { typeof(int), typeof(int), typeof(int) }); 20 methodNew.Invoke(genericObj, new object[] { 1, 2, 3 }); 21 } 22 { 23 //调用泛型类中的泛型方法 24 Type genericType = assembly.GetType("Reflection.DB.SqlServer.GenericClass`3"); //泛型类有三个泛型参数 25 Type genericNewType = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); 26 object objGeneric = Activator.CreateInstance(genericNewType); 27 MethodInfo method = genericNewType.GetMethod("Show"); 28 method.Invoke(objGeneric, new object[] { 1, 2, 3 }); 29 } 30 31 } 32 #endregion
5.1反射字段和属性
1 #region 反射字段和属性 2 { 3 4 People people = new People(); 5 people.Id = 1; 6 people.Name = "ABC"; 7 people.Description = "一个中国人"; 8 Type type = typeof(People); 9 object oPeople = Activator.CreateInstance(type); 10 foreach (var item in type.GetProperties()) 11 { 12 //获取属性名称和默认值 13 Console.WriteLine("{0}={1}",item.Name,item.GetValue(people)); 14 } 15 16 foreach (var item in type.GetFields()) 17 { 18 //获取字段名称和默认值 19 Console.WriteLine("{0}={1}", item.Name, item.GetValue(people)); 20 } 21 22 } 23 #endregion
1 public T Get<T>(int id) 2 { 3 Type type = typeof(T); 4 string columnStrings = string.Join(",", type.GetProperties().Select(p => string.Format("[{0}]", p.Name))); 5 string sql = string.Format("SELECT {0} FROM {1} WHERE ID={2}", columnStrings, type.Name, id); 6 object obj = Activator.CreateInstance(type); 7 using (SqlConnection connection = new SqlConnection(connectionString)) 8 { 9 connection.Open(); 10 SqlCommand command = new SqlCommand(sql, connection); 11 SqlDataReader reader = command.ExecuteReader(); 12 if (reader.Read()) 13 { 14 foreach (var item in type.GetProperties()) 15 { 16 item.SetValue(obj, reader[item.Name]); 17 } 18 } 19 connection.Close(); 20 } 21 22 return (T)obj; 23 }
调用代码:
region 反射拼装sql,从数据库中读取数据 { SqlServerHelper sqlHelper = new SqlServerHelper(); Company company = sqlHelper.Get<Company>(1); Type type = typeof(Company); foreach (var item in type.GetProperties()) { Console.WriteLine("{0}={1}", item.Name, item.GetValue(company)); } } #endregion