代码改变世界

动态方法与动态代理(上篇)

2011-06-22 14:57  熬夜的虫子  阅读(620)  评论(0编辑  收藏  举报

所谓动态方法,是指在程序运行阶段生成的并且能够执行的方法. 动态方法可以关联到任何已有的模块(Module)中,作为现有模块的扩展. 动态方法可以访问模块中所有类型及其成员.  

实现动态方法依赖于:反射发出(System.Reflection.Emit)、 MSIL语言  

•微软中间语言(MSIL)是将.Net代码转化为机器语言的一个中间过程。它是一种介于高级语言和汇编语言的伪汇编语言,也是.Net框架的基础,任何高级应用都是在其之上发展起来的。尽管2.0之后,微软相继推出的各个版本都包含很多新的功能,但MSIL语言却基本上没有发生变化,可谓是“万变不离其宗”,了解MSIL语言是实现动态方法的前提,千里之行始于足下
•.Net自带的查看MSIL的工具:ILDASM

  String.ToLower()方法的MSIL代码

 

•基本语法

操作指令

说明

ldarg

将参数加载到堆栈顶部

例如:ldarg.0 将第一个参数加载到堆栈

starg 

将栈顶元素保存到参数

例如:starg.0 将栈顶数据保存到第一个参数

ldloc  

将本地变量加载到堆栈顶部

例如:ldloc.0 将第一个变量加载到堆栈

stloc  

将栈顶元素保存到本地变量

例如:stloc.0 将栈顶数据保存到第一个变量

ldc

将常量数字加载到堆栈顶部

例如:ldc.i4.2 将2加载到堆栈,i4表示int32数字

类似的还有用于加载字符串的ldstr、加载和保存字段的ldfld和stfld、加载数字常量的ldc等等,这些指令执行的操作很好记,以ld开头的就是加载到堆栈,以st开头的就是从堆栈上取回值

call

callvirt

作用都是调用方法,但用法有区别:call用于执行非虚函数或静态方法;callvirt用于执行虚函数或实例方法,注意,这里所说的是一般情况,编译器为了优化也有例外。

 

ret

方法返回,如果有返回值,则将其从被调者堆栈转移到调用者堆栈顶部

nop

空操作

br

无条件跳转,br.s是br的短格式

例如:br.s L_0002 无条件跳转到L_0002行

brtrue

操作数非空或非False时跳转

例如:brtrue.s L_0002 当操作数为真时跳转到L_0002行

brfalse

操作数为空、为False或为0时跳转

例如:brfalse.s L_0002 当操作数为假时跳转到L_0002行

相关的跳转语言还有beq、bge、ble和blt等等,执行跳转语言后,堆栈元素将被清除,即堆栈顶部不包含元素,b和br都是branch的缩写  

add

将两个操作数相加,结果放到堆栈顶部

sub

将两个操作数相减,结果放到堆栈顶部

 

•反射发出 

反射发出不是将文本形式的C#代码编译成DLL

    •使用IL语言动态的产生可执行代码
    •相关类位于System.Reflection.Emit命名空间中
    •反射发出创建的是MSIL代码,而不是产生源代码
    •IL操作指令包含在OpCodes中
 
•Demo:动态方法演示
    class Program
    {
        
static void Main(string[] args)
        {
            Type[] paramTypes 
= new Type[] { typeof(string) };

            DynamicMethod hello 
= new DynamicMethod("Hello"null, paramTypes, typeof(Program).Module);
            ILGenerator ilGen 
= hello.GetILGenerator();
            ilGen.Emit(OpCodes.Ldarg_0);

            MethodInfo writeLineMethod 
= typeof(Console).GetMethod("WriteLine"new Type[] { typeof(string) });

            ilGen.Emit(OpCodes.Call, writeLineMethod);

            ilGen.Emit(OpCodes.Ret);

            Action
<string> invoker = (Action<string>)hello.CreateDelegate(typeof(Action<string>));

            invoker(
"你好,我来自于动态方法");
        }
    }