反射到底有什么用?
以前,假设我们要不借助任何类库直接解析Json协议的东西,比如{“a”:"A","b":"B","c":"C"},并且我们需要将他们赋给一个与之对应的实体类。那么我们需要写出如下的代码来解析
//这只是一段伪代码 while(str.Length!=0){ //在一个大的while里面遍历整个字符串//这里省去解析的函数//用判断读到的名称,然后对应相应的属性进行初始化。 if(name=="a"){ SetA(value);//为属性A赋值 }else if(name=="b"){ //为属性B赋值 SetA(value); }else{ ... }}
从上面代码中,可以知道,当要为一个实体类赋值和解析的属性比较少的时候,我们要写的代码还是可以让人接受的,但是一旦实体类的代码一多,那么整个过程就非常地恶心。通过反射,我们可以获取一个实体类中的信息,通过获取运行时的函数信息,我们又可以动态地调用函数,为实体类动态赋值。以上代码如果用反射的相关方法来写的话,就会变得异常简洁。
//这只是一段伪代码 while(str.Length!=0){ //在一个大的while里面遍历整个字符串//这里省去解析的函数//用判断读到的名称,然后通过反射调用相应的属性进行初始化。 MethodInfo mMethodInfo = ClassA.GetMethod(name); mMethodInfo.Invoke(obj1, null);
…}
说了这么久,给反射下个定义
反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息): – 引用自《》
System.Reflection.MemberInfo System.Reflection.EventInfo System.Reflection.FieldInfo System.Reflection.MethodBase System.Reflection.ConstructorInfo System.Reflection.MethodInfo System.Reflection.PropertyInfo System.Type System.Reflection.Assembly
来一段代码示例
我们有一个HelloWorld类,我们想要通过反射动态地获取他的信息,并动态地调用他的方法。
public class HelloWorld { string myName = null; public HelloWorld(string name) { myName = name; } public HelloWorld() : this(null) { } public string Name { get { return myName; } } public void SayHello() { if (myName == null) System.Console.WriteLine("\t\tHello World"); else System.Console.WriteLine("\t\tHello," + myName); } }
下面我们将应用反射进行获取方法名、动态创建类的实例、动态调用方法
static void Main(string[] args) { System.Console.WriteLine("列出程序集中的所有类型"); Assembly mAssembly = Assembly.LoadFrom("ReflectionExample.exe"); Console.WriteLine("程序集的名称是: {0}\n\n", mAssembly.GetName()); Type[] mType = mAssembly.GetTypes(); Console.WriteLine("以下是程序集里面的类型"); for (int i = 0; i < mType.Length; i++) { Console.WriteLine("\t{0}.{1}", i, mType[i].Name); } Type Ht = typeof(HelloWorld); MethodInfo[] mMethodInfo = Ht.GetMethods();//利用反射获取HelloWorld里所有的方法 Console.WriteLine("Hello World类中所有的方法:"); for (int i = 0; i < mMethodInfo.Length; i++) { //输出类里面所有的方法名 Console.WriteLine("\t{0}.{1}", i, mMethodInfo[i].Name); } Console.WriteLine("利用Activator.CreateInstance创建实例"); object obj1 = Activator.CreateInstance(Ht);//利用Activator.CreateInstance创建不同的实例obj1和obj2 string name = "ChenZheRong"; object obj2 = Activator.CreateInstance(Ht, name); MethodInfo mSayHello = Ht.GetMethod("SayHello"); Console.WriteLine("\tobj1的输出"); mSayHello.Invoke(obj1, null); Console.WriteLine("\tobj2的输出"); mSayHello.Invoke(obj2, null); }
结果截图如下所示
要彻底地了解反射,我们还需要了解.NET可执行应用程序的结构。
.NET可执行应用程序结构
程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。
应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 (3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。 (4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。 (5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。 (6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 (7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。 (8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。 System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。
参考连接