学习系列之反射
一 反射概述
反射是一种机制,通过这种机制我们可以知道一个未知类型的类型信息.比如,有一个对象a,这个对象不是我们定义的,也许是通过网络捕捉到的,也许是使用泛型定义的,但我们想知道这个对象的类型信息,想知道这个对象有哪些方法或者属性什么的.甚至我们想进一步调用这个对象的方法.关键是现在我们只知道它是一个对象,不知道它的类型,自然不会知道它有哪些方法等信息.这时我们该怎么办?反射机制就是解决这么一个问题的.通过反射机制我们可以知道未知类型对象的类型信息,并且使用它
· 通过反射可以提供类型信息,从而使得我们开发人员在运行时能够利用这些信息构造和使用对象。
· 反射机制允许程序在执行过程中动态地添加各种功能。
二 反射的核心类:System.Type类
- 许多支持反射的类都位于System.Reflection命名空间中,他们是.net Reflection API的一部分,所以在使用的反射的程序中一般都要使用 System.Reflection的命名空间。
- System. Type类包装了类型,因此是整个反射子系统的核心,这个类中包含了很多属性和方法,使用这些属性和方法可以在运行时得到类型的信息。
- Type类派生于System.Reflection.MemberInfo抽象类
注意:
- MemberType属性的返回类型为MemberTypes,这是一个枚举,它定义了用于表示不同成员的类型值。这些值包括: MemberTypes.Constructor, MemberTypes.Method, MemberTypes.Field, MemberTypes.Event, MemberTypes.Property。因此可以通过检查MemberType属性来确定成员的类型,例如,在MemberType属性的值为MemberTypes.Method时,该成员为方法
- MemberInfo类还包含两个与特性相关的抽象方法:
GetCustomAttributes() :获得与主调对象关联的自定义特性列表。
IsDefined(): 确定是否为主调对象定义了相应的特性。
GetCustomAttributesData():返回有关自定义特性的信息(特性稍后便会提到)
当然除了MemberInfo类定义的方法和属性外,Type类自己也添加了许多属性和方法:如下表(只列出一些常用的,太多了,自己可以转定义Type类看下)
三 System.Reflection.Assembly类
通过Assembly可以动态加载程序集,并查询程序集内部信息.Assembly中有三种方法加载程序集:Load,Loadform,LoadFile.
*如果引用了命名空间,则就直接用Load方法,参数里写上命名空间+类名就可加载。
*若仅仅知道一个dll文件,则就要用LoadFrom方法,参数里直接填写完整的路径。LoadFrom只能用于加载不同标识的程序集,即唯一的程序集,不能加载标识相同但路径不同的程序集。
*Loadfile,加载指定路径上的程序集文件;与上述两方法不同的是:它不会加载此程序集中引用的其他的程
序集,且不会加载相同标识的程序集。
举例:
Assembly assembly = Assembly.Load("MyAssembly"); //引用命名空间 Assembly assembly2 = Assembly.LoadFrom("D:\testDll.dll"); Assembly dll = Assembly.LoadFile(Environment.CurrentDirectory + "\\testDll.dll"); //通过dll文件去反射其中所有的类型,但不会加载引用的程序集</span>
三 使用反射
通过使用Type类定义的方法和属性,我们能够在运行时获得类型的各种具体信息。这是一个非常强大的功能。我们一旦得到类型信息,就可以调用其构造函数,方法,和属性。可见,反射是允许使用编译时不可用的代码的。
四种关键的反射技术:
1.获取方法的信息
2.调用方法
3.构造对象
4.从程序集中加载类型
四 获取成员的信息
public class RefClass : Object { private int _test3; private int _test1 { get; set; } protected int Test2 { get; set; } public int Test3 { get; set; } private static void Show2() { } public static void Show3() { } public void Show() { } } class Program { static void Main(string[] args) { Type t = typeof(RefClass); Func<MemberTypes, string> getType = (x) => { switch (x) { case MemberTypes.Field: { return "字段"; } case MemberTypes.Method: { return "方法"; } case MemberTypes.Property: { return "属性"; } default: { return "未知"; } } }; MemberInfo[] mis = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static); foreach (MemberInfo mi in mis) { Console.WriteLine("类型成员的名称{0},类型:{1}", mi.Name,getType(mi.MemberType)); } Console.ReadLine(); } }
五 获取字段的信息
public class RefClass { private int _test3; public int Test3 { get; set; } private int _test1 { get; set; } protected int Test2 { get; set; } private static void Show2() { } public static void Show3() { } public void Show() { } } class Program { static void Main(string[] args) { Type t = typeof(RefClass); RefClass rc = new RefClass(); rc.Test3 = 3; FieldInfo[] fis = t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static); foreach (FieldInfo fi in fis) { fi.SetValue(rc,100); Console.WriteLine("字段成员的名称{0},字段类型:{1},rc中的值{2}", fi.Name,fi.FieldType,fi.GetValue(rc)); } Console.ReadLine(); } }
六 获取属性的信息
public class RefClass { private int _test3; public int Test3 { get; set; } private int _test1 { get; set; } protected int Test2 { get; set; } private static void Show2() { } public static void Show3() { } public void Show() { } } class Program { static void Main(string[] args) { Type t = typeof(RefClass); RefClass rc = new RefClass(); PropertyInfo[] fis = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static); foreach (PropertyInfo fi in fis) { MethodInfo getinfo = fi.GetGetMethod(true); Console.WriteLine("get方法的名称{0} 返回值类型:{1} 参数数量:{2} MSIL代码长度:{3} 局部变量数量:{4}", getinfo.Name, getinfo.ReturnType.ToString(), getinfo.GetParameters().Count(), getinfo.GetMethodBody().GetILAsByteArray().Length, getinfo.GetMethodBody().LocalVariables.Count); MethodInfo setinfo = fi.GetSetMethod(true); Console.WriteLine("set方法的名称{0} 返回值类型:{1} 参数数量:{2} MSIL代码长度:{3} 局部变量数量:{4}", setinfo.Name, setinfo.ReturnType.ToString(), setinfo.GetParameters().Count(), setinfo.GetMethodBody().GetILAsByteArray().Length, setinfo.GetMethodBody().LocalVariables.Count); setinfo.Invoke(rc, new object[] { 123 }); //设置值 object obj = getinfo.Invoke(rc, null); Console.WriteLine("方法名:{0} 内部值:{1}", fi.Name, obj);//读出值 } Console.ReadLine(); } }
七 获取方法的信息
BindingFlags是一个枚举,枚举值有(很多只列出5个吧):
- DeclareOnly:仅获取指定类定义的方法,而不获取所继承的方法;
- Instance:获取实例方法
- NonPublic: 获取非公有方法
- Public: 获取共有方法
- Static:获取静态方法
public class RefClass { private int _test3; private int _test1 { get; set; } protected int Test2 { get; set; } public int Test3 { get; set; } private static void Show2() { } public static string Show3(string s) { int b; int c; return s; } public string Show(string s) { string a;
return s; } } class Program { static void Main(string[] args) { RefClass rc = new RefClass(); Type t = typeof(RefClass); MethodInfo[] mis = t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static); foreach (MethodInfo mi in mis) { if ((mi.GetParameters().Count() > 0) && (mi.GetParameters()[0].ParameterType == typeof(string))) { var a = new[] { "123" }; object obj = mi.Invoke(rc, a); MethodBody mbody = mi.GetMethodBody(); Console.WriteLine("拥有参数的方法名:{0} 返回值类型:{1} 参数1类型:{2} 参数1名称:{3} 方法调用后返回的值:{4}", mi.Name, mi.ReturnType.ToString(), mi.GetParameters()[0].ParameterType.ToString(), mi.GetParameters()[0].Name, obj.ToString()); } else { MethodBody mbody = mi.GetMethodBody(); Console.WriteLine("没有参数的方法名:{0} 返回值类型:{1}", mi.Name, mi.ReturnType.ToString()); } } Console.ReadKey(); } }
八 动态创建对象
class MyClass { int x; int y; public MyClass(int i) { x = y + i; } public MyClass(int i, int j) { x = i; y = j; } public int sum() { return x + y; } } class Program { static void Main() { Type t=typeof(MyClass); int val; ConstructorInfo[] ci = t.GetConstructors(); //获取构造函数的列表 int x;//记录构造函数的个数 for (x = 0; x < ci.Length; x++) { ParameterInfo[] pi = ci[x].GetParameters(); if (pi.Length == 2) break; } if (x == ci.Length) { return; } object[] consargs = new object[2]; consargs[0] = 10; consargs[1] = 20; object reflectOb = ci[x].Invoke(consargs);//实例化一个这个构造函数有两个参数的类型对象,如果参数为空,则为null //实例化后,调用MyClass中的方法 MethodInfo[] mi = t.GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); foreach (MethodInfo m in mi) { if (m.Name.Equals("sum", StringComparison.Ordinal)) { val = (int)m.Invoke(reflectOb, null); //由于实例化类型对象的时候是用的两个参数的构造函数,所以这里返回的结构为30 Console.WriteLine(" sum is " + val); //输出 sum is 30 } } Console.ReadKey(); } }