C#通过Emit动态生成代码,超简单

什么是Emit

    Emit是反射的一个比较高级的一个功能,使用Emit可以从零开始动态的创建程序集及类,从而提高了程序的灵活性。

实现步骤

1、首先需要声明一个程序集名称,

 // specify a new assembly name var assemblyName = new AssemblyName("Kitty");

2、从当前应用程序域获取程序集构造器,.

 // create assembly builder var assemblyBuilder = AppDomain.CurrentDomain  .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

有几种动态程序集构造访问限制:

  • AssemblyBuilderAccess.Run; 表示程序集可被执行,但不能被保存。  

  • AssemblyBuilderAccess.Save; 表示程序集可被保存,但不能被执行。  

  • AssemblyBuilderAccess.RunAndSave; 表示程序集可被保存并能被执行。

  • AssemblyBuilderAccess.ReflectionOnly; 表示程序集只能用于反射上下文环境中,不能被执行。 

  • AssemblyBuilderAccess.RunAndCollect; 表示程序集可以被卸载并且内存会被回收。

3、在程序集中构造动态模块,

 // create module builder var moduleBuilder = assemblyBuilder.DefineDynamicModule("KittyModule", "Kitty.exe");

模块即是代码的集合,一个程序集中可以有多个模块。并且理论上讲,每个模块可以使用不同的编程语言实现,例如C#/VB。

4、构造一个类型构造器,

 // create type builder for a class var typeBuilder = moduleBuilder.DefineType("HelloKittyClass", TypeAttributes.Public);

通过类型构造器定义一个方法,获取方法构造器,获得方法构造器的IL生成器,通过编写IL代码来定义方法功能。

// create method buildervar methodBuilder = typeBuilder.DefineMethod(  "SayHelloMethod",  MethodAttributes.Public | MethodAttributes.Static,  null,  null);
// then get the method il generatorvar il = methodBuilder.GetILGenerator();
// then create the method functionil.Emit(OpCodes.Ldstr, "Hello, Kitty!");il.Emit(OpCodes.Call,  typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine"));il.Emit(OpCodes.Pop); // we just read something here, throw it.il.Emit(OpCodes.Ret);

5 创建类型,

 // then create the whole class type var helloKittyClassType = typeBuilder.CreateType();

如果当前程序集是可运行的,则设置一个程序入口,

 // set entry point for this assembly assemblyBuilder.SetEntryPoint(helloKittyClassType.GetMethod("SayHelloMethod"));

6、将动态生成的程序集保存成磁盘文件,

 // save assembly assemblyBuilder.Save("Kitty.exe");

此时,通过反编译工具,将Kitty.exe反编译成代码,

using System;
public class HelloKittyClass{  public static void SayHelloMethod()  {    Console.WriteLine("Hello, Kitty!");    Console.ReadLine();  }}

运行结果,
C#通过Emit动态生成代码,超简单

完整代码

using System;using System.Reflection;using System.Reflection.Emit;
namespace EmitIntroduction{  class Program  {    static void Main(string[] args)    {      // specify a new assembly name      var assemblyName = new AssemblyName("Kitty");
      // create assembly builder      var assemblyBuilder = AppDomain.CurrentDomain        .DefineDynamicAssembly(assemblyName,          AssemblyBuilderAccess.RunAndSave);
      // create module builder      var moduleBuilder =        assemblyBuilder.DefineDynamicModule(          "KittyModule", "Kitty.exe");
      // create type builder for a class      var typeBuilder =        moduleBuilder.DefineType(          "HelloKittyClass", TypeAttributes.Public);
      // create method builder      var methodBuilder = typeBuilder.DefineMethod(        "SayHelloMethod",        MethodAttributes.Public | MethodAttributes.Static,        null,        null);
      // then get the method il generator      var il = methodBuilder.GetILGenerator();
      // then create the method function      il.Emit(OpCodes.Ldstr, "Hello, Kitty!");      il.Emit(OpCodes.Call,        typeof(Console).GetMethod(        "WriteLine", new Type[] { typeof(string) }));      il.Emit(OpCodes.Call,        typeof(Console).GetMethod("ReadLine"));      il.Emit(OpCodes.Pop); // we just read something here, throw it.      il.Emit(OpCodes.Ret);
      // then create the whole class type      var helloKittyClassType = typeBuilder.CreateType();
      // set entry point for this assembly      assemblyBuilder.SetEntryPoint(        helloKittyClassType.GetMethod("SayHelloMethod"));
      // save assembly      assemblyBuilder.Save("Kitty.exe");
      Console.WriteLine(        "Hi, Dennis, a Kitty assembly has been generated for you.");      Console.ReadLine();    }  }}

下载完整代码:

https://github.com/gaochundong/LearningEmit