一、定义
反射是一种 通过动态读取程序集,获取其中的类型元数据,并且对其进行访问的 技术。
二、用法
首先创建一个Person类。
1 public class Person 2 { 3 private int _size; 4 public string Name { get; set; } 5 public int Age { get; set; } 6 public int Gender { get; set; } 7 public void Say() 8 { 9 Console.WriteLine("hello !"); 10 } 11 12 public void SayHello() 13 { 14 Console.WriteLine("hello ,everyone !"); 15 } 16 17 void Introduce() 18 { 19 Console.WriteLine("i am wesley"); 20 } 21 }
1.Type对象
接下来使用反射中的重要对象Type访问Person中的类型元数据。使用Type对象,有两种方式。
第一种方式:Type personType = typeof(Person);
1 Type personType = typeof(Person); 2 MemberInfo[] members = personType.GetMembers(); 3 for (int i = 0; i < members.Length; i++) 4 { 5 Console.WriteLine(members[i].Name); 6 }
输出结果:
1 //get_Name 2 //set_Name 3 //get_Age 4 //set_Age 5 //get_Gender 6 //set_Gender 7 //Say 8 //SayHello 9 //ToString 10 //Equals 11 //GetHashCode 12 //GetType 13 //.ctor 14 //Name 15 //Age 16 //Gender
包括编译器自动生成的与属性对应的方法,继承自object的方法,但是不包括私有方法。如果需要访问私有方法,需要用其他方式。
第二种方式: Person person = new Person(); Type personType= person.GetType();
1 Person person = new Person(); 2 Type personType= person.GetType(); 3 4 //获取所有方法,私有的方法不能获取 5 MethodInfo[] methods = personType.GetMethods(); 6 for (int i = 0; i < methods.Length; i++) 7 { 8 Console.WriteLine(methods[i].Name); 9 } 10 11 //所有属性 12 PropertyInfo[] properties= personType.GetProperties(); 13 for (int i = 0; i < properties.Length; i++) 14 { 15 Console.WriteLine(properties[i].Name); 16 }
用Type对象还能访问其他类型元数据,具体可以查看文档或者对象中的成员。
2.Assembly
先创建一个类库,里面有类,接口,委托等,代码如下:
1 namespace _01TestDLL 2 { 3 class Test 4 { 5 } 6 7 public class Person 8 { 9 private int _size; 10 public string Name { get; set; } 11 public int Age { get; set; } 12 public int Gender { get; set; } 13 public void Say() 14 { 15 Console.WriteLine("hello !"); 16 } 17 18 public void SayHello() 19 { 20 Console.WriteLine("hello ,everyone !"); 21 } 22 23 void Introduce() 24 { 25 Console.WriteLine("i am wesley"); 26 } 27 28 public int Add(int n1,int n2) 29 { 30 return n1 + n2; 31 } 32 33 //public int Add(int n1, int n2,int n3) 34 //{ 35 // return n1 + n2 + n3; 36 //} 37 } 38 39 class MyClass 40 { } 41 42 public delegate void M1Delegate(); 43 44 delegate void M2Delegate(); 45 46 interface IDriveAble { } 47 48 public interface IFlyAble 49 { 50 void Fly(); 51 } 52 53 public class Student 54 { 55 56 } 57 58 public class Teacher : IFlyAble 59 { 60 public void Fly() 61 { 62 Console.WriteLine("i can fly ,see me fly high !"); 63 } 64 } 65 }
把上面的类库生成dll,用Assembly读取。
显示dll中的所有类型元数据:
1 Assembly assembly = Assembly.LoadFile(@"F:BaseWork 1TestDLLinDebug 1TestDLL.dll"); 2 3 //Console.WriteLine(assembly.GetType().Name); 4 5 //这种方式输出程序集中的所有类型元数据 6 Type[] types1 = assembly.GetTypes(); 7 foreach (var item in types1) 8 { 9 Console.WriteLine(item.Name); 10 } 11 12 //只显示public的类型元数据 13 Type[] types = assembly.GetExportedTypes(); 14 foreach (var item in types) 15 { 16 Console.WriteLine(item.Name); 17 }
访问Person类中无参无返回值的Say方法:
1 #region 调用程序集中无参无返回值的方法 2 Type personType = assembly.GetType("_01TestDLL.Person"); 3 4 MethodInfo method = personType.GetMethod("Say"); 5 6 object obj = Activator.CreateInstance(personType); 7 8 //我们不能直接创建要调用的方法所在的类的对象(如果可以创建对象,我们直接可以调用该类中的方法了,没必要再用反射),所以用上一行代码创建对象 9 method.Invoke(obj, null);//第一个参数:当前要调用的方法所在的类的对象;第二个参数:要调用的方法的参数列表 10 #endregion
调用Person类中有参数有返回值的方法(Add(int n1,int n2)):
1 #region 调用程序集中有参数有返回值的方法 2 Type personType = assembly.GetType("_01TestDLL.Person"); 3 4 MethodInfo method = personType.GetMethod("Add"); 5 object obj = Activator.CreateInstance(personType); 6 int res = (int)method.Invoke(obj, new object[] { 1, 2 }); 7 Console.WriteLine(res); 8 #endregion
调用Person类中Add的重载方法(Add(int n1,int n2,int n3)):
1 #region 调用程序集中重载的方法 2 //如果Add方法有重载,则需要区分方法是否重载 3 Type personType = assembly.GetType("_01TestDLL.Person"); 4 MethodInfo method = personType.GetMethod("Add", new Type[] { typeof(int), typeof(int), typeof(int) }); 5 object obj = Activator.CreateInstance(personType); 6 int res = (int)method.Invoke(obj, new object[] { 1, 2, 3 }); 7 Console.WriteLine(res); 8 #endregion
给属性赋值,取值
1 #region 给属性赋值,并且取值 2 Type personType= assembly.GetType("_01TestDLL.Person"); 3 PropertyInfo proper= personType.GetProperty("Name"); 4 //object obj= assembly.CreateInstance("_01TestDLL.Person");//和下面的代码效果一样 5 object obj = Activator.CreateInstance(personType); 6 proper.SetValue(obj, "张三"); 7 8 string name= proper.GetValue(obj, null).ToString(); ; 9 Console.WriteLine(name); 10 #endregion
先在Person类中添加一个方法和构造函数,然后调用构造函数,创建对象
方法和构造函数
1 public Person(string name,int age) 2 { 3 this.Name = name; 4 this.Age = age; 5 } 6 7 public void GetPropertiesValue() 8 { 9 Console.WriteLine(this.Name+" "+this.Age); 10 }
1 #region 调用构造函数,创建对象 2 Type typePerson = assembly.GetType("_01TestDLL.Person"); 3 ConstructorInfo ctor = typePerson.GetConstructor(new Type[] { typeof(string), typeof(int) }); 4 5 object obj= ctor.Invoke(new object[] { "张三", 18 }); 6 7 MethodInfo method= typePerson.GetMethod("GetPropertiesValue"); 8 method.Invoke(obj, null); 9 10 #endregion
3.Type的其他常用方法和属性
先创建类和获取程序集:
1 namespace _02TestDLL 2 { 3 public class Person 4 { 5 public void Introduce() 6 { 7 Console.WriteLine("我是人类"); 8 } 9 } 10 11 public interface IFlyAble 12 { 13 void Fly(); 14 } 15 16 public abstract class MyAbstractClass 17 { 18 19 } 20 21 public static class MyStaticClass 22 { 23 24 } 25 26 public class Student : Person, IFlyAble 27 { 28 public void Fly() 29 { 30 throw new NotImplementedException(); 31 } 32 } 33 }
程序集:
1 Assembly assembly = Assembly.LoadFile(@"F:BaseWork 2TestDLLinDebug 2TestDLL.dll");
IsAssignableFrom():判断当前实例是不是可以接收传入的实例
1 Type typePerson = assembly.GetType("_02TestDLL.Person"); 2 3 Type typeStudent = assembly.GetType("_02TestDLL.Student"); 4 5 Type typeIFlyAble = assembly.GetType("_02TestDLL.IFlyAble"); 6 7 bool bPerson = typePerson.IsAssignableFrom(typeStudent); 8 9 Console.WriteLine(bPerson); 10 11 //输出true
IsInstanceOfType():判断指定的实例是不是当前类型的实例
1 Type typePerson = assembly.GetType("_02TestDLL.Person"); 2 Type typeStudent = assembly.GetType("_02TestDLL.Student"); 3 Object obj = Activator.CreateInstance(typeStudent); 4 5 bool b = typePerson.IsInstanceOfType(obj); 6 Console.WriteLine(b); 7 //输出true
IsSubclassOf():判断当前Type表示的类是不是从指定的类派生的
1 Type typePerson = assembly.GetType("_02TestDLL.Person"); 2 Type typeStudent = assembly.GetType("_02TestDLL.Student"); 3 bool b = typeStudent.IsSubclassOf(typePerson); 4 Console.WriteLine(b); 5 //输出true
IsAbstract:判断当前Type表示的类是不是抽象的,包括接口和静态类
1 Type typeMyStaticClass = assembly.GetType("_02TestDLL.MyStaticClass"); 2 Type typeMyAbstractClass = assembly.GetType("_02TestDLL.MyAbstractClass"); 3 Type typeIFlyAble = assembly.GetType("_02TestDLL.IFlyAble"); 4 5 bool b1 = typeMyStaticClass.IsAbstract; 6 Console.WriteLine(b1); 7 8 bool b2 = typeMyAbstractClass.IsAbstract; 9 Console.WriteLine(b2); 10 11 bool b3 = typeIFlyAble.IsAbstract; 12 Console.WriteLine(b3); 13 //输出true
用IsAbstract属性判断时,发现静态类,接口也返回true,反编译后查看IL语言,发现静态类,接口其实就是抽象类。