Emit学习笔记

C# 2014-07-15 09:55

之前一直有看到过Emit,一直没有下定决心学一下,昨天的Dapper很好用,想学习的话呢需要先理解Emit,刚好就算做学习储备了,写个学习笔记先


简单入门,从网上找的

如果只是想要创建一个Dynamic Method 那么可以直接使用HelloWorld例子中使用的DynamicMethod类来创建一个动态方法,并在构造函数时传入它所依附的类或者模块

        /// <summary>
        /// 用来调用动态方法的委托
        /// </summary>
        private delegate void HelloWorldDelegate(); 
        static void Main(string[] args)
        { 
            //定义一个名为HelloWorld的动态方法,没有返回值,没有参数
            DynamicMethod helloWorldMethod = new DynamicMethod("HelloWorld", null, null);

            //创建一个MSIL生成器,为动态方法生成代码
            ILGenerator helloWorldIL = helloWorldMethod.GetILGenerator();

            //将要输出的Hello World!字符创加载到堆栈上
            helloWorldIL.Emit(OpCodes.Ldstr, "blog.wx6.org");
            //调用Console.WriteLine(string)方法输出Hello World!
            helloWorldIL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            //方法结束,返回
            helloWorldIL.Emit(OpCodes.Ret);

            //完成动态方法的创建,并且获取一个可以执行该动态方法的委托
            HelloWorldDelegate HelloWorld = (HelloWorldDelegate)helloWorldMethod.CreateDelegate(typeof(HelloWorldDelegate));

            //执行动态方法,将在屏幕上打印Hello World!
            HelloWorld(); 

            Console.Read(); 
        }


使用Emit一般包括以下步骤:

1)        创建一个新的程序集(可以选择存在与内存中或者持久化到硬盘);

2)        在程序集内创建一个模块;

3)        在模块内创建动态类;

4)        给动态类添加动态方法、属性、事件,等;

5)        生成相关的IL代码;

6)        返回创建出来的类型或持久化到硬盘中。

string name = "EmitExamples.DynamicFibonacci";
string asmFileName = name   ".dll";

#region Step 1 构建程序集 
//创建程序集名
AssemblyName asmName = new AssemblyName(name); 
//获取程序集所在的应用程序域
//你也可以选择用AppDomain.CreateDomain方法创建一个新的应用程序域
//这里选择当前的应用程序域
AppDomain domain = AppDomain.CurrentDomain; 
//实例化一个AssemblyBuilder对象来实现动态程序集的构建
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); 
#endregion

#region Step 2 定义模块 
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name, asmFileName); 
#endregion

#region Step 3 定义类型 
TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public); 
#endregion

#region Step 4 定义方法 
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
    "Calc",
    MethodAttributes.Public,
    typeof(Int32),
    new Type[] { typeof(Int32) }); 
#endregion

#region Step 5 实现方法 
ILGenerator calcIL = methodBuilder.GetILGenerator();  
//定义标签lbReturn1,用来设置返回值为1
Label lbReturn1 = calcIL.DefineLabel();
//定义标签lbReturnResutl,用来返回最终结果
Label lbReturnResutl = calcIL.DefineLabel(); 
//加载参数1,和整数1,相比较,如果相等则设置返回值为1
calcIL.Emit(OpCodes.Ldarg_1);
calcIL.Emit(OpCodes.Ldc_I4_1);
calcIL.Emit(OpCodes.Beq_S, lbReturn1); 
//加载参数1,和整数2,相比较,如果相等则设置返回值为1
calcIL.Emit(OpCodes.Ldarg_1);
calcIL.Emit(OpCodes.Ldc_I4_2);
calcIL.Emit(OpCodes.Beq_S, lbReturn1); 
//加载参数0和1,将参数1减去1,递归调用自身
calcIL.Emit(OpCodes.Ldarg_0);
calcIL.Emit(OpCodes.Ldarg_1);
calcIL.Emit(OpCodes.Ldc_I4_1);
calcIL.Emit(OpCodes.Sub);
calcIL.Emit(OpCodes.Call, methodBuilder); 
//加载参数0和1,将参数1减去2,递归调用自身
calcIL.Emit(OpCodes.Ldarg_0);
calcIL.Emit(OpCodes.Ldarg_1);
calcIL.Emit(OpCodes.Ldc_I4_2);
calcIL.Emit(OpCodes.Sub);
calcIL.Emit(OpCodes.Call, methodBuilder); 
//将递归调用的结果相加,并返回
calcIL.Emit(OpCodes.Add);
calcIL.Emit(OpCodes.Br, lbReturnResutl); 
//在这里创建标签lbReturn1
calcIL.MarkLabel(lbReturn1);
calcIL.Emit(OpCodes.Ldc_I4_1); 
//在这里创建标签lbReturnResutl
calcIL.MarkLabel(lbReturnResutl);
calcIL.Emit(OpCodes.Ret); 
#endregion

#region Step 6 收获 
Type type = typeBuilder.CreateType(); 
assemblyBuilder.Save(asmFileName); 
object ob = Activator.CreateInstance(type); 
for (int i = 1; i < 10; i  )
{
    Console.WriteLine(type.GetMethod("Calc").Invoke(ob, new object[] { i }));
} 
#endregion


原文链接  http://www.cnblogs.com/yingql/archive/2009/03/20/1418007.html


Leave a Reply