Reflection.Emit的使用1

Reflection.Emit的作用是能够在程序运行的时候动态生成Class,Method和Field.

这样带来的好处是在程序运行的时候产生DynamicProxy,从而可以达到AOP拦截的作用(就是AOP.NET的实现原理).

由于Emit中提供了TypeBuilder(生成Class的类),MethodBuilder(生成Method的类)以及FieldBuilder(生成类的成员变量的类)等等.

由于MethodBuilder只能生成函数的申明,不能生成函数的执行代码,所以要想生成一个完整的函数,就不可避免的要用到ILGenerator类.

ILGenerator只能通过Emit(...)函数来增加直接的IL代码,所以使用Emit的时候也得明白一些关于IL的知识.

在编程中,对于函数的调用是经常的,像Win32汇编一样,调用一个函数前要将其参数压入到栈中...

IL中要求参数压入到栈中,要以从左到右的方式,也就是先把函数声明的最左边的参数压到栈中,再依次把其如的参数分别压到栈中,比如:

函数定义:

public void Show(int,string,object);

通过InvokeShow来调用这个函数,InvokeShow的定义如下:

public void InvokeShow(int,string,object)

 

ILGenerator methodIL=TypeBuilder.DefineMethod(...).GetGenerator();

除了静态函数外,其他所有的函数的实际的参数都会在最左边多一位,就是this.所以这里的参数应该是从1开始的.

//假设Show函数的MethodInfo是这个InvokeShow的类的一个成员变量,其FieldBuilder名称为show_MethodInfo;

//这里,我们先把对象压到栈中,由于是类的成员,所以前面要加this

methodIL.Emit(Opcodes.Ldarg_0);

methodIL.Emit(Opcodes.Ldfld,show_MethodInfo);

//参数入栈

methodIL.Emit(Opcodes.Ldarg_1);

methodIL.Emit(Opcodes.Ldarg_2);

methodIL.Emit(Opcodes.Ldarg_3);

//调用函数

methodIL.Emit(Opcodes.Callvirt,typeof(MethodInfo).GetMethod("Invoke"));

//由于MethodInfo.Invoke函数有返回值,而ncokeShow函数没有返回值,所以要把返回值给Pop出去,保持栈的平衡

methodIL.Emit(OpCodes.Pop);

methodIL.Emit(OpCodes.Ret);

上面就是一个简单的函数调用的Emit实现了.

上面的代码中使用到了FieldBuilder 的show_MethodInfo.现在我们看看如何给这个成员变量赋值.

函数定义如下:

public void Initial(MethodInfo showMethod);

IL代码:

methodIL.Emit(OpCodes.Ldarg_0);

methodIL.Emit(OpCodes.Ldarg_1);

methodIL.Emit(OpCodes.Stfld.show_MethodInfo);

methodIL.Emit(OpCodes.Ret);

这样,就可以给类的成员变量进行赋值了

 

现怎么生成函数中的临时变量了?

通过ILGenerator的DeclareLocal函数可以生成临时变量:

LocalBuilder local=methodIL.DeclareLocal(typeof(System.String));

//给其赋值,把第一个参数的值传给 这个local

methodIL.Emit(OpCodes.Ldarg_1);

methodIL.Emit(OpCodes.Stloc,local);

//使用这个变量

methodIL.Emit(OpCodes.Ldloc,local);

 

默认情况下,定义的LocalBuilder是从0开始按顺序来的,也就是说,如果local是定义的第一个LocalBuilder,上面的代码也就可以写成下面这样:

methodIL.Emit(OpCodes.Ldarg_1);

methodIL.Emit(OpCodes.Stloc,_0);

//使用这个变量

 methodIL.Emit(OpCodes.Ldloc_0);

你可能感兴趣的:(reflection)