反射无处不在,我们天天在使用。VS的智能提示,就是通过反射获取到类的属性、方法等。还有反编译工具也是通过反射实现。
反射就是动态获取程序集的元数据(提供程序集的类型信息)的功能。
反射就是动态获取程序集中的元数据来操作类型的
Type类实现反射的一个重要的类,通过它我们可以获取类中的所有信息,包括方法、属性等。可以动态调用累的属性、方法。Type是对类的描述。
反射就是直接通过 .dll 来创建对象,调用成员。
通过类型元数据来获取对象的一些相关信息,并且还可以实例化对象调用方法等,这个就叫做 ”反射” 。
反射让创建对象的方式发生了改变。
编译器的智能提示就是反射的一个应用。
Type类的使用
通过类获得Type: Type t = typeof( person )
通过对象获得类的Type: Type t = p.GetType( )
动态加载程序集
string path = @"F:\MyCSharp\练习\练习\ClassLibrary1\bin\Debug\ClassLibrary1.dll"; //加载程序集 Assembly asm = Assembly.LoadFile(path);
调用 Assembly 的 GetExportedTypers 方法可以得到 Assembly 中定义的所有 public 类型
Type[] types = asm.GetExportedTypes();//获得程序集中定义的所有 public 类型 返回值是一个类型数组
调用 Assembly 的 GetTpye( name ) 方法可以得到 Assembly 中定义的全名为 name 的类型信息
//获取指定的某个类型,必须写该类型的"全名"(完全限定名称:ClassLibrary1.Person) Type typePerson = asm.GetType("ClassLibrary1.Person");
GetConstructor ( 参数列表 ) ; //这是一个找到带参数的构造函数
Activator.CreateInstance( Type t ) 会动态调用类的无参构造函数创建一个对象,返回值就是创建的对象,如果类没有无参构造函数机会报错
string path = @"F:\MyCSharp\练习\练习\ClassLibrary1\bin\Debug\ClassLibrary1.dll"; //加载程序集 Assembly asm = Assembly.LoadFile(path); //获得某个类型的Type Type typeStudent = asm.GetType("ClassLibrary1.Student"); Type typePerson = asm.GetType("ClassLibrary1.Person"); Type typeIFlyable = asm.GetType("ClassLibrary1.IFlyable"); //使用CreateInstance(Type t) 创建对象 object student = Activator.CreateInstance(typeStudent);//调用的是无参的构造函数 object person = Activator.CreateInstance(typePerson);//调用的是无参的构造函数
Type类的方法:在编写调用插件的程序时,需要做一系列验证。
bool IsAssignableFrom( Type c ); 判断当前的类型的变量是不是可以接受 c 类型变量的赋值。
1 //1、IsAssignableFrom(),就是验证是否可以将某个类型的对象赋值给另外一个类型的变量 2 string path = @"F:\MyCSharp\练习\练习\ClassLibrary1\bin\Debug\ClassLibrary1.dll"; 3 //加载程序集 4 Assembly asm = Assembly.LoadFile(path); 5 //获得某个类型的Type 6 Type typeStudent = asm.GetType("ClassLibrary1.Student"); 7 Type typePerson = asm.GetType("ClassLibrary1.Person"); 8 Type typeIFlyable = asm.GetType("ClassLibrary1.IFlyable"); 9 //返回true 表示可以将 typeStudnet 的对象赋值给 typePerson 类型 10 Console.WriteLine(typePerson.IsAssignableFrom(typeStudent)); 11 //是否可以把 typeStudent 对象赋值给 typeIFlyable 类型变量 12 Console.WriteLine(typeIFlyable.IsAssignableFrom(typePerson)); 13 //是否可以把 typeStudent 对象赋值给 typeIFlyable 类型变量 14 Console.WriteLine(typeIFlyable.IsAssignableFrom(typeStudent)); 15 Console.ReadKey();
bool IsInstanceOfType( object o ); 判断对象o是否是当前类的实例(当前类可以是o的类、父类、接口)
1 string path = @"F:\MyCSharp\练习\练习\ClassLibrary1\bin\Debug\ClassLibrary1.dll"; 2 //加载程序集 3 Assembly asm = Assembly.LoadFile(path); 4 //获得某个类型的Type 5 Type typeStudent = asm.GetType("ClassLibrary1.Student"); 6 Type typePerson = asm.GetType("ClassLibrary1.Person"); 7 Type typeIFlyable = asm.GetType("ClassLibrary1.IFlyable"); 8 object student = Activator.CreateInstance(typeStudent); 9 object person = Activator.CreateInstance(typePerson); 10 //person 这个对象是否是当前指定的 typePerson 的对象 11 Console.WriteLine(typePerson.IsInstanceOfType(person));//true 12 //student 这个对象是否是当前指定的 typePerson 的对象 13 Console.WriteLine(typePerson.IsInstanceOfType(student));//true 14 //person 这个对象是否是当前指定的 typeStudent 的对象 15 Console.WriteLine(typeStudent.IsInstanceOfType(person));//false 16 //student 这个对象是否是当前指定的 typeStudent 的对象 17 Console.WriteLine(typeStudent.IsInstanceOfType(student));//true 18 //person 这个对象是否是当前指定的 typeIFlyable 的对象 19 Console.WriteLine(typeIFlyable.IsInstanceOfType(person));//false 20 //student 这个对象是否是当前指定的 typeIFlyable 的对象 21 Console.WriteLine(typeIFlyable.IsInstanceOfType(student));//true 22 Console.ReadKey();
bool IsSubclassOf( Type c ); 判断当前类是否是类c的子类。(与接口无关)
1 //3、IsSubclassOf(Type c) 判断当前类是否是类 c 的子类,只是类,没有接口的事 2 string path = @"F:\MyCSharp\练习\练习\ClassLibrary1\bin\Debug\ClassLibrary1.dll"; 3 //加载程序集 4 Assembly asm = Assembly.LoadFile(path); 5 //获得某个类型的Type 6 Type typeStudent = asm.GetType("ClassLibrary1.Student"); 7 Type typePerson = asm.GetType("ClassLibrary1.Person"); 8 Type typeIFlyable = asm.GetType("ClassLibrary1.IFlyable"); 9 //创建指定类型的对象 10 object student = Activator.CreateInstance(typeStudent); 11 object person = Activator.CreateInstance(typePerson); 12 //判断 typeStudent 是否是 typePerson 的子类 13 Console.WriteLine(typeStudent.IsSubclassOf(typePerson));//true 14 //判断 typePerson 是否是 typeIFlyable 的子类 15 Console.WriteLine(typePerson.IsSubclassOf(typeIFlyable));//false 16 //判断 typeStudent 是否是 typeIFlyable 的子类 17 Console.WriteLine(typeStudent.IsSubclassOf(typeIFlyable));//false 18 Console.ReadKey();
IsAbstract 判断是否为抽象的,包含接口
1 //4、IsAbstract 判断是否为抽象的,含接口 2 string path = @"F:\MyCSharp\练习\练习\ClassLibrary1\bin\Debug\ClassLibrary1.dll"; 3 4 //加载程序集 5 Assembly asm = Assembly.LoadFile(path); 6 7 //获得某个类型的Type 8 Type typeStudent = asm.GetType("ClassLibrary1.Student"); 9 Type typePerson = asm.GetType("ClassLibrary1.Person"); 10 Type typeIFlyable = asm.GetType("ClassLibrary1.IFlyable"); 11 Type typeMyclass1 = asm.GetType("ClassLibrary1.MyClass1"); 12 Type typeMyclass2 = asm.GetType("ClassLibrary1.MyClass2"); 13 14 //创建指定类型的对象 15 object student = Activator.CreateInstance(typeStudent); 16 object person = Activator.CreateInstance(typePerson); 17 18 //判断是否为抽象的,含接口 19 Console.WriteLine(typeStudent.IsAbstract);//false 20 Console.WriteLine(typePerson.IsAbstract);//false 21 Console.WriteLine(typeIFlyable.IsAbstract);//true 22 Console.WriteLine(typeMyclass1.IsAbstract);//true 23 Console.WriteLine(typeMyclass2.IsAbstract);//true 24 25 Console.ReadKey();
MemberInfo类 抽象类,有很多子类,下面所有类都继承自 MemberInfo 类:
PropertyInfo 获取属性
1 //所有的属性 2 PropertyInfo[] properties = typePerson.GetProperties(); 3 //通过循环输出每一个属性的名称 4 for (int i = 0; i < properties.Length; i++) 5 { 6 //循环输出 7 Console.WriteLine(properties[i].Name); 8 } 9 Console.ReadKey();
主要成员:
CanRead、CanWrite、PropertyType属性类型;
SetValue、GetValue:读取值、设置值第一个参数是实例对象,因为set、get要针对具体实例,最后一个参数 null 。pInfo.SetValue( p1, 30, null );
MethodInfo 获取方法
1 //获取 Person 类中的所有的方法 2 MethodInfo[] methods = typePerson.GetMethods(); 3 //遍历获取到的所有方法的数组 4 for (int i = 0; i < methods.Length; i++) 5 { 6 //输出所有方法的方法名 7 Console.WriteLine(methods[i].Name); 8 } 9 Console.ReadKey();
1 //获得Person类名字为SayHi的方法,并且是没有任何参数的方法 2 MethodInfo method = typePerson.GetMethod("SayHi")
调用这个方法
1 MethodInfo method = typePerson.GetMethod("SayHi"); 2 //判断获得的方法是否为空 3 if (method != null) 4 { 5 //因为SayHi()方法是一个实例方法,不是静态方法,所以调用SayHi()方法的时候,必须在某个对象上调用,所以method.Invoke() 需要传递一个具体的Person对象进去 6 object obj = Activator.CreateInstance(typePerson);//创建一个Person对象 7 //调用Invoke() 方法要把person创建的对象传进来 8 method.Invoke(obj, null);//调用SayHi()方法,如果这个方法没有参数第二个参数为null 9 } 10 else 11 { 12 Console.WriteLine("找不懂啊你要调用的方法"); 13 } 14 Console.ReadKey();
//获得方法名为 SayHi 的重载方法(第二个参数为对应类型的参数:typeof(参数相应类型)) MethodInfo method = typePerson.GetMethod("SayHi", new Type[] { typeof(string), typeof(string) }); if (method != null) { //因为SayHi()方法是一个实例方法,不是静态方法,所以调用SayHi()方法的时候,必须在某个对象上调用,所以method.Invoke() 需要传递一个具体的Person对象进去 object obj = Activator.CreateInstance(typePerson);//创建一个Person对象 method.Invoke(obj, new object[] { "张三", "吃了吗" });//调用SayHi(string s1,string s2)重载方法 } else { Console.WriteLine("找不到你要调用的方法"); } Console.ReadKey();
FieldInfo 获取字段
1 //获得所有的字段 2 FieldInfo[] fields = typePerson.GetFields(); 3 //遍历每个字段 4 for (int i = 0; i < fields.Length; i++) 5 { 6 //输出每个字段名 7 Console.WriteLine(fields[i].Name); 8 } 9 Console.ReadKey();
EventInfo 获取事件