Emit動態生成代碼

Emit動態生成代碼

引用:秒懂C#經過Emit動態生成代碼html

首先須要聲明一個程序集名稱,git

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

從當前應用程序域獲取程序集構造器,github

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

有幾種動態程序集構造訪問限制:編程

  • AssemblyBuilderAccess.Run; 表示程序集可被執行,但不能被保存。  
  • AssemblyBuilderAccess.Save; 表示程序集可被保存,但不能被執行。  
  • AssemblyBuilderAccess.RunAndSave; 表示程序集可被保存並能被執行。
  • AssemblyBuilderAccess.ReflectionOnly; 表示程序集只能用於反射上下文環境中,不能被執行。 
  • AssemblyBuilderAccess.RunAndCollect; 表示程序集能夠被卸載而且內存會被回收。

在程序集中構造動態模塊,編程語言

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

模塊便是代碼的集合,一個程序集中能夠有多個模塊。而且理論上講,每一個模塊能夠使用不一樣的編程語言實現,例如C#/VB。
構造一個類型構造器,函數

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

經過類型構造器定義一個方法,獲取方法構造器,得到方法構造器的IL生成器,經過編寫IL代碼來定義方法功能。工具

// 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);

建立類型,ui

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

若是當前程序集是可運行的,則設置一個程序入口,this

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

將動態生成的程序集保存成磁盤文件,spa

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

此時,經過反編譯工具,將Kitty.exe反編譯成代碼,

using System;

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

運行結果,

完整代碼

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();
    }
  }
}

下載完整代碼

進一步閱讀使用Emit生成構造函數和屬性

相關文章
相關標籤/搜索