前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >秒懂C#通过Emit动态生成代码

秒懂C#通过Emit动态生成代码

作者头像
郑子铭
发布2023-10-30 11:08:33
2290
发布2023-10-30 11:08:33
举报
文章被收录于专栏:DotNet NB && CloudNative

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

代码语言:javascript
复制
代码语言:javascript
复制
 // specify a new assembly name
var assemblyName = new AssemblyName("Kitty");

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

代码语言:javascript
复制
代码语言:javascript
复制
 // create assembly builder
 var assemblyBuilder = AppDomain.CurrentDomain
   .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

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

  • AssemblyBuilderAccess.Run; 表示程序集可被执行,但不能被保存。  
  • AssemblyBuilderAccess.Save; 表示程序集可被保存,但不能被执行。  
  • AssemblyBuilderAccess.RunAndSave; 表示程序集可被保存并能被执行。
  • AssemblyBuilderAccess.ReflectionOnly; 表示程序集只能用于反射上下文环境中,不能被执行。 
  • AssemblyBuilderAccess.RunAndCollect; 表示程序集可以被卸载并且内存会被回收。

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

代码语言:javascript
复制
代码语言:javascript
复制
 // create module builder
 var moduleBuilder = assemblyBuilder.DefineDynamicModule("KittyModule", "Kitty.exe");
代码语言:javascript
复制
模块即是代码的集合,一个程序集中可以有多个模块。并且理论上讲,每个模块可以使用不同的编程语言实现,例如C#/VB。
构造一个类型构造器,
代码语言:javascript
复制
 // create type builder for a class
var typeBuilder = moduleBuilder.DefineType("HelloKittyClass", TypeAttributes.Public);

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

代码语言:javascript
复制
// 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);

创建类型,

代码语言:javascript
复制
代码语言:javascript
复制
// then create the whole class type
 var helloKittyClassType = typeBuilder.CreateType();
代码语言:javascript
复制
如果当前程序集是可运行的,则设置一个程序入口,
代码语言:javascript
复制
代码语言:javascript
复制
 // set entry point for this assembly
 assemblyBuilder.SetEntryPoint(helloKittyClassType.GetMethod("SayHelloMethod"));
代码语言:javascript
复制
将动态生成的程序集保存成磁盘文件,
代码语言:javascript
复制
代码语言:javascript
复制
 // save assembly
 assemblyBuilder.Save("Kitty.exe");
代码语言:javascript
复制
此时,通过反编译工具,将Kitty.exe反编译成代码,
代码语言:javascript
复制
using System;

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

运行结果,

完整代码

代码语言:javascript
复制
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();
    }
  }
}

下载完整代码:

github.com/gaochundong/LearningEmit

进一步阅读使用Emit生成构造函数和属性:cnblogs.com/gaochundong/archive/2013/06/01/csharp_emit_create_constructor_properties.html

推荐阅读:

推荐一个基于 .NET 开发的开源工作流项目

推荐一个使用 .NET 和 Angular 开发的在线任务管理工具

基于.NET的强大文件格式开源转换工具

字符串 --- 不可变性与驻留池

Dotnet工具箱:开源、免费的纯前端工具网站,带你探索10大工具分类和73个实时在线小工具

.NET高性能开发-位图索引

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 完整代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档