C# 的反射机制

195 阅读7分钟

反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌,还可以直接创建对象,即使这个对象的类型在编译时还不知道。

  1. 反射的用途:
 (1)使用`Assembly`定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。 
 (2)使用`Module`了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 
 (3)使用`ConstructorInfo`了解构造函数的名称、参数、访问修饰符(如`pulic``private`)和实现详细信息(如`abstract``virtual`)等。 
 (4)使用`MethodInfo`了解方法的名称、返回类型、参数、访问修饰符(如`pulic``private`)和实现详细信息(如`abstract``virtual`)等。
 (5)使用`FiedInfo`了解字段的名称、访问修饰符(如`public``private`)和实现详细信息(如`static`)等,并获取或设置字段值。
 (6)使用`EventInfo`了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 
 (7)使用`PropertyInfo`了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。 
 (8)使用`ParameterInfo`了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
  1. 反射用到的命名空间:
 (1`System.Reflection`
 (2`System.Type`
 (3`System.Reflection.Assembly`
  1. 反射用到的主要类:
 (1`System.Type` 类--通过这个类可以访问任何给定数据类型的信息。
 (2`System.Reflection.Assembly`类--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。
  1. System.Type类:

System.Type类对于反射起着核心的作用。但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。

 // 获取给定类型的Type引用有3种常用方式:
 // 使用 C# typeof 运算符。
 Type t = typeof(string);
 // 使用对象GetType()方法。
 string s = "grayworm";
 Type t = s.GetType(); 
 // 还可以调用Type类的静态方法GetType()。
 Type t = Type.GetType("System.String");
  1. 获取给定类型的Type引用有3种常用方式:
 // 使用 C# typeof 运算符。
 Type t = typeof(string);
 // 使用对象GetType()方法。
 string s = "grayworm";
 Type t = s.GetType(); 
 // 还可以调用Type类的静态方法GetType()。
 Type t = Type.GetType("System.String");

上面这三类代码都是获取string类型的Type,在取出string类型的Type引用t后,我们就可以通过t来探测string类型的结构了。

 string n = "grayworm";
 Type t = n.GetType();
 foreach(MemberInfo mi in t.GetMembers())
 {
     Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name);
 }
  1. Type类的属性:
 Name 数据类型名
 FullName 数据类型的完全限定名(包括命名空间名)
 Namespace 定义数据类型的命名空间名
 IsAbstract 指示该类型是否是抽象类型
 IsArray  指示该类型是否是数组
 IsClass  指示该类型是否是类
 IsEnum  指示该类型是否是枚举
 IsInterface  指示该类型是否是接口
 IsPublic 指示该类型是否是公有的
 IsSealed 指示该类型是否是密封类
 IsValueType 指示该类型是否是值类型
  1. Type类的方法:
 GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息;
 GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息;
 GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息;
 GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息;
 GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息;
 GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息;
 GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法;

查看类中的构造方法:

 NewClass nc = new NewClass();
 Type t = nc.GetType();
 ConstructorInfo[] ci = t.GetConstructors(); // 获取类的所有构造函数
 foreach(ConstructorInfo c in ci)  // 遍历每一个构造函数
 {
     ParameterInfo[] ps = c.GetParameters(); // 取出每个构造函数的所有参数
     foreach(ParameterInfo pi in ps) // 遍历并打印该构造函数的所有参数
     {
         Console.WriteLine(pi.ParameterType.TOString() + " " + pi.Name + ",");
     }
     Console.WriteLine();
 }

用构造函数动态生成对象:

 Type t = typeof(NewClass);
 Type[] pt = new Type[2];
 pt[0] = typeof(string);
 pt[1] = typeof(string);
 // 根据参数类型获取构造函数
 ConstructorInfo ci = t.GetConstructor(pt);
 // 构造Object数组, 作为构造函数的输入参数
 object[] obj = new object[2]{"wiki", "dualseason.com"};
 object o = ci.Invoke(obj);
 // 调用生成的对象的方法测试是否对象成功生成
 ((NewClass)o).show();

用Activator生成对象:

 Type t = typeof(NewClass);
 // 构造函数的参数
 object[] obj = new object[2] {"wiki", "dualseason.com"};
 // 用Activator的CreateInstanc静态方法, 生成新对象
 object o = Activator.CreateInstance(t, "wiki", "dualseason.com");
 // ((NewClass)o).show();

查看类中的属性

 NewClass nc = new NewClass();
 Type t = nc.GetType();
 PropertyInfo[] pis = t.GetProperties();
 foreach(PropertyInfo pi in pis)
 {
     Console.WriteLine(pi.Name);
 }

查看类中的public方法

 NewClass nc = new NewClass();
 Type t = nc.GetType();
 MethodInfo[] mis = t.GetMethods();
 foreach(MethodInfo mi in mis)
 {
     Console.WriteLine(mi.ReturnType + " " + mi.Name);
 }

查看类中的public字段

 NewClass nc = new NewClass();
 Type t = nc.GetType();
 FieldInfo[] fis = t.GetFields();
 foreach(FieldInfo fi in fis)
 {
     Console.WriteLine(fi.Name);
 }

用反射生成对象,并调用属性、方法和字段进行操作

 NewClass nc = new NewClass();
 Type t = nc.GetType();
 Object obj = Activator.CreateInstance(t);
 // 取得ID字段
 FieldInfo fi = t.GetField("ID");
 // 给ID字段赋值
 fi.SetValue(obj, "k001");
 // 取得MyName属性
 PropertyInfo pi1 = t.GetProperty("MyName");
 // 给MyName属性赋值
 pi1.SetValue(obj, "grayworm", null);
 PropertyInfo pi2 = t.GetProperty("MyInfo");
 pi2.SetValue(obj, "dualseason.com", null);
 // 取得show方法
 MethodInfo mi = t.GetMethod("show");
 // 调用show方法
 mi.Invoke(obj, null);
  1. System.Reflection.Assembly类

    Assembly类可以获得程序集的信息,也可以动态加载程序集,以及在程序集中查找类型信息,并创建该类型的实例。

    使用Assembly类可以降低程序集之间的耦合,有利于软件结构的合理化。

 // 通过程序集名称返回Assembly对象
 Assemb ass = Assembly.Load("ClassLibary831"); //dll名称无后缀
 // 通过DLL文件名称返回Assembly对象
 Assembly ass = Assembly.LoadFrom("ClassLibary831.dll");// 带后缀或者完整路径
 // 通过Assembly获取程序集的类, 参数必须是类的全名
 Type t = ass.GetType("ClassLibary831.NewClass");
 // 通过Assembly获取程序集所有类
 Type[] t = ass.GetTypes();
 // 通过程序集名称反射
 Assembly ass = Assembly.Load("ClassLibary831");
 Type t = ass.GetType("ClassLibary831.NewClass");
 object o = Activator.CreateInstance(t, "wiki", "http://dualseason.com");
 MethodInfo mi = t.GetMethod("show");
 mi.Invoke(o, null);
 // 通过DLL文件全名反射所有类型
 Assembly ass = Assembly.LoadFrom("LeadDream.dll");
 Type[] ts = ass.GetTypes();
 foreach(Type t in ts)
 {
     if(t.FullName == "LeadDream.PropertyManagement.Handler")
     {
         object o = Activator.CreateInstance(t);
     }
 }
  1. 应用实例
 // dll名称无后缀, 从当前目录加载
 Assembly assembly = Assembly.Load("LeadDream.DB.MySql");
 // 完整路径的加载甚至可以是别的目录,加载不会错,但是如果没有依赖项,使用的时候会错
 Assembly assembly = Assembly.LoadFile(@"D:\dualseason\LeadDream.DB.MySql.dll");
 // 带后缀或者完整路径
 Assembly assembly2 = Assembly.LoadFrom("LeadDream.DB.MySql.dll");
 foreach (var item in assembly.GetModules())
 {
     Console.WriteLine(item.FullyQualifiedName);
 }
 foreach (var item in assembly.GetTypes())
 {
     Console.WriteLine(item.FullName);
 }
 // 获取类型信息
 Type type = assembly.GetType("LeadDream.DB.MySql.MySqlHelper");
 // 创建对象,oDBHelper是objec不能调用oDBHelper.Query(),但实际上方法是有的只是编译器不认可,需要类型转换
 object oDBHelper = Activator.CreateInstance(type);
 // 类型转换
 IDBHelper iDBHelper = (IDBHelper)oDBHelper;
 // 方法调用
 iDBHelper.Query();
 // appSetting.conf
 "IDBHelper": {
     "DLLName": "LeadDream.DB.MySql",
     "TypeName": "LeadDream.DB.MySql.MySqlHelper"
 },
 ​
 public class Factory
 {
     private IConfiguration Configuration { get; }
     public Startup(IConfiguration configuration)
     {
         Configuration = configuration;
     }
     private static string DllName = ConfiguationManager.AppSettings["IDBHelper:DLLName"];
     private static string TypeName = ConfiguationManager.AppSettings["IDBHelper:TypeName"];
     public static IDBHelper CreateHelper() 
     {
         Assembly assembly = Assembly.Load(DllName);
         Type type = assembly.GetType(TypeName);
         object oDBHelper = Activator.CreateInstance(type);
         IDBHelper iDBHelper = (IDBHelper)oDBHelper;
         return iDBHelper;
     }
 }
 ​
 // IOC原理:反射 + 配置文件 + 工厂
 public void Main(string[] args)
 {
     IDBHelper iDBHelper = Factory.CreateHelper();
     iDBHelper.Query();
 }
 // 测量反射的额外所需时间
 namespace MyReflection
 {
     public class Monitor
     {
         public static void Show()
         {
             long commonTime = 0;
             long reflectionTime = 0;
             {
                 Stopwatch watch = new Stopwatch();
                 watch.Start();
                 for(int i = 0; i < 100000; i++)
                 {
                     IDBHelper iDBHelper = new SqlServerHelper();
                     iDBHelper.Query();
                 }
                 watch.Stop();
                 commonTime = watch.ElapsedMilliseconds;
             }
             {
                 Stopwatch watch = new Stopwatch();
                 watch.Start();
                 Assembly assembly = Assembly.Load("LeadDream.DB.SqlServer");
                 Type dbHelperType = assembly.GetType("LeadDream.DB.SqlServer.SqlServerHelper");
                 for(int i = 0; i< 100000; i++)
                 {
                     object oDBHelper = Activator.CreateInstance(dbHelperType);
                     IDBHelper dbHelper = (IDBHelper)oDBHelper;
                     dbHelper.Query();
                 }
                 watch.Stop();
                 reflectionTime = watch.ElapsedMilliseconds;
             }
             Console.WriteLine("commonTime={0} reflectionTime={1}", commonTime, reflectionTime);
         }
     }
 }
 // 补充单例模式代码
 namespace LeadDream.DB.SqlServer
 {
     public sealed class Singleton
     {
         private static Singleton _Singleton = null;
         private Singleton()
         {
             Console.WriteLine("Singleton被构建");
         }
         
         static Singleton()
         {
             _Singleton = new Singleton();
         }
         
         public static Singleton GetInstance()
         {
             return _Singleton;
         }
     }
 }
 // Reflection + Instance
 SingleTon singleton = new Singleton();
 Singleton singleton1 = Singleton.GetInstance();
 Singleton singleton2 = Singleton.GetInstance();
 Singleton singleton3 = Singleton.GetInstance();
 ​
 {
     Assembly assembly = Assembly.Load("LeadDream.DB.SqlServer");
     Type type = assembly.GetType("LeadDream.DB.SqlServer.Singleton");
     Singleton singleton4 = (Singleton)Activator.CreateInstance(type, true);
     Singleton singleton5 = (Singleton)Activator.CreateInstance(type, true);
     Singleton singleton6 = (Singleton)Activator.CreateInstance(type, true);
 }
 {
     Assembly assembly = Assembly.Load("LeadDream.DB.SqlServer");
     Type type = assembly.GetType("LeadDream.DB.SqlServer.ReflectionTest");
     object oReflectionTest1 = Activator.CreateInstance(type);
     object oReflectionTest2 = Activator.CreateInstance(type, new object[] { 123 });
     object oReflectionTest3 = Activator.CreateInstance(type, new object[] { "123" });
 }
 {
     Assembly assembly = Assembly.Load("LeadDream.DB.SqlServer");
     Type type = assembly.GetType("LeadDream.DB.SqlServer.ReflectionTest");
     object oGeneric = Activator.CreateInstance(type);
     Type newType = Type.MakeGenericType(new Type { typeof(int), typeof(string), typeof(DateTime) });
     object oGeneric = Activator.CreateInstance(newType);
 }
 // LeadDream.DB.SqlServer
 namespace LeadDream.DB.SqlServer
 {
     public class ReflectionTest
     {
         #region Identity
         public ReflectionTest()
         {
             Console.WriteLine("这里是{0}无参数构造函数", this.GetType());
         }
         public ReflectionTest(string name)
         {
             Console.WriteLine("这里是{0} 有参数构造函数", this.GetType());
         }
 ​
         public ReflectionTest(int id)
         {
             Console.WriteLine("这里是{0} 有参数构造函数", this.GetType());
         }
         #endregion
 ​
         #region Method
         public void Show1()
         {
             Console.WriteLine("这里是{0}的Show1", this.GetType());
         }
         public void Show2(int id)
         {
 ​
             Console.WriteLine("这里是{0}的Show2", this.GetType());
         }
         public void Show3(int id, string name)
         {
             Console.WriteLine("这里是{0}的Show3", this.GetType());
         }
         public void Show3(string name, int id)
         {
             Console.WriteLine("这里是{0}的Show3_2", this.GetType());
         }
         public void Show3(int id)
         {
 ​
             Console.WriteLine("这里是{0}的Show3_3", this.GetType());
         }
         public void Show3(string name)
         {
 ​
             Console.WriteLine("这里是{0}的Show3_4", this.GetType());
         }
         public void Show3()
         {
 ​
             Console.WriteLine("这里是{0}的Show3_1", this.GetType());
         }
         private void Show4(string name)
         {
             Console.WriteLine("这里是{0}的Show4", this.GetType());
         }
         public static void Show5(string name)
         {
             Console.WriteLine("这里是{0}的Show5", typeof(ReflectionTest));
         }
         #endregion
     }
 }
 // MVC URL地址--类名称 + 方法名称
 Assembly assembly = Assembly.Load("LeadDream.DB.SqlServer");
 Type type = assembly.GetType("LeadDream.DB.SqlServer.ReflectionTest");
 object oReflectionTest = Activator.CreateInstance(type);
 foreach(var item in type.GetMethods())
 {
     Console.WriteLine(item.Name);
 }
 // oReflectionTest.Show1();
 {
     MethodInfo method = type.GetMethod("Show1");
     method.Invoke(oReflectionTest, null);
 }
 {
     MethodInfo method = type.GetMethod("Show2");
     method.Invoke(oReflectionTest, new object[] { 123 });
 }
 {
     MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(int) });
     method.Invoke(oReflectionTest, new object[] { 123 });
 }
 {
     MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(string) });
     method.Invoke(oReflectionTest, new object[] { "Ant" });
 }
 {
     MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });
     method.Invoke(oReflectionTest, new object[] { 234, "W" });
 }
 {
     MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
     method.Invoke(oReflectionTest, new object[] { "W", 234 });
 }
 {
     MethodInfo method = type.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic);
     method.Invoke(oReflectionTest, new object[] { "天空之上" });
 }
 {
     Type typeGenericDouble = assembly.GetType("LeadDream.DB.SqlServer.GenericDouble");
     Type newType = typeGenericDouble.MakeGenericType(new Type[] { typeof(int) });
     object oGeneric = Activator.CreateInstance(newType);
     MethodInfo method = newType.GetMethod("Show");
     MethodInfo methodNew = method.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) });
     methodNew.Invoke(oGeneric, new object[] { 123, "流浪诗人", DateTime.Now });
 }
 namespace LeadDream.DB.SqlServer
 {
     public class 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);
         }
     }
 ​
     public class 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);
         }
     }
 }
 // ORM => Reflection + Property/Field
 People people = new People();
 people.Id = 123;
 people.Name = "ReactSpring";
 people.Description = "岭梦科技CEO";
 //    Console.WriteLine($"people.Id={people.Id}");
 //    Console.WriteLine($"people.Name={people.Name}");
 //    Console.WriteLine($"people.Description={people.Description}");
 Type type = typeof(People);
 object oPeople = Activator.CreateInstance(type);
 //    foreach (var prop in type.GetProperties())
 //    {
 //        Console.WriteLine(type.Name);
 //        Console.WriteLine(prop.Name);
 //        Console.WriteLine(prop.GetValue(oPeople));
 //        if (prop.Name.Equals("Id"))
 //        {
 //            prop.SetValue(oPeople, 234);
 //        }
 //        else if (prop.Name.Equals("Name"))
 //        {
 //            prop.SetValue(oPeople, "风潇潇");
 //        }
 //        Console.WriteLine($"{type.Name}.{prop.Name}={prop.GetValue(oPeople)}");
 //    }
 foreach (var field in type.GetFields())
 {
     Console.WriteLine(type.Name);
     Console.WriteLine(field.Name);
     Console.WriteLine(field.GetValue(oPeople));
     if (field.Name.Equals("Description"))
     {
         field.SetValue(oPeople, "首席技术执行官");
     }
     Console.WriteLine($"{type.Name}.{field.Name}={field.GetValue(oPeople)}");
 }
 ​
 {
     People people = new People();
     people.Id = 123;
     prople.Name = "小春";
     people.Description = "CEO";
     
     //    {   //硬编码
     //        //PeopleDTO peopleDTO = (PeopleDTO)people;
     //        PeopleDTO peopleDTO = new PeopleDTO()
     //        {
     //            Id = people.Id,
     //            Name = people.Name,
     //            Description = people.Description
     //        };
     //    }
     {
         Type typePeople = typeof(People);
         Type typePeopleDTO = typeof(PeopleDTO);
         object peopleDTO = Activator.CreateInstance(typePeopleDTO);
         foreach(var prop in typePeopleDTO.GetProperties())
         {
             object value = typePeople.GetProperty(prop.Name).GetValue(prople);
             prop.SetValue(peopleDTO, value);
         }
         foreach(var field in typePeopleDTO.GetFields())
         {
             object value = typePeople.GetField(field.Name).GetValue(people);
             field.SetValue(peopleDTO, value);
         }
     }
 }