.NET Core中Emit的使用

news/2024/5/19 22:25:54 标签: .netcore, c#

反射允许我们在运行时获取对象的相关信息,创建对象的实例,执行方法。Emit是作为反射的一个比较高级的功能。使用Emit,可以从零开始动态的创建程序集及类。提供程序的灵活性。本文主要介绍.NET Core中Emit的使用。

1、程序集(Assembly)

程序集构成了 .NET 应用程序的部署、版本控制、重用、激活范围和安全权限的基本单元。 程序集是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元。 程序集采用可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式,是 .NET 应用程序的构建基块 。 它们向公共语言运行时提供了注意类型实现代码所需的信息。在 .NET 和 .NET Framework 中,可从一个或多个源代码文件生成程序集。 在 .NET Framework 中,程序集可以包含一个或多个模块。使用System.Reflection.Emit可以动态创建程序集。

2、模块(Module)

模块是程序集内代码的逻辑集合,每个模块可以使用不同的语言编写,大多数情况下,一个程序集包含一个模块。程序集包括了代码、版本信息、元数据等。模块是没有 Assembly 清单的 Microsoft 中间语言(MSIL)文件。

3、Emit的使用

Emit可以使用MSIL指令动态编写程序逻辑,然后将指令编译成程序集。通过编写代码的方式动态创建程序。比如软件授权,可以输入授权信息后,生成一个授权的DLL,使用Emit实现动态AOP框架等。

1).NET Framework中使用Emit

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
  class Program
  {
    static void Main(string[] args)
    {
      CreateAssembly();
      LoadAssembly();
      Console.ReadKey();
    }
    public static void LoadAssembly()
    {
      var ass = AppDomain.CurrentDomain.Load("MyAssembly");
      var m = ass.GetModule("MyModule");
      var ts = m.GetTypes();
      var t = ts.FirstOrDefault();
      if (t != null)
      {
        object obj = Activator.CreateInstance(t);
        var me = t.GetMethod("MyMethod");
        me.Invoke(obj, null);
      }
    }
    public static void CreateAssembly()
    {
      //定义一个程序集的名称
      var asmName = new AssemblyName("MyAssembly");
      //首先就需要定义一个程序集
      var defAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
      //定义一个构建类
      var defModuleBuilder = defAssembly.DefineDynamicModule("MyModule", "MyAssembly.dll");
      //定义一个类
      var defClassBuilder = defModuleBuilder.DefineType("MyClass", TypeAttributes.Public);
      //定义一个方法
      var defMethodBuilder = defClassBuilder.DefineMethod("MyMethod",
        MethodAttributes.Public,
        null,//返回类型
        null//参数类型
        );
      //获取IL生成器
      var il = defMethodBuilder.GetILGenerator();
      //定义一个字符串
      il.Emit(OpCodes.Ldstr, "生成的第一个程序");
      //调用一个函数
      il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
      //返回到方法开始(返回)
      il.Emit(OpCodes.Ret);
      //创建类型
      defClassBuilder.CreateType();
      //保存程序集
      defAssembly.Save("MyAssembly.dll");
    }
  }
}

2).NET Core中使用Emit

using System;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApp2
{
    class Program
    {
        public static void Main()
        {
            AssemblyName aName = new AssemblyName("ChefDynamicAssembly");
            AssemblyBuilder ab =
                AssemblyBuilder.DefineDynamicAssembly(
                    aName,
                    AssemblyBuilderAccess.Run);
            ModuleBuilder mb = ab.DefineDynamicModule(aName.Name + ".dll");
            TypeBuilder tb = mb.DefineType("Commander");
            var attrs = MethodAttributes.Public;
            // 使用类型构建器创建一个方法构建器
            MethodBuilder methodBuilder = tb.DefineMethod("Do", attrs, typeof(string), Type.EmptyTypes);
            // 通过方法构建器获取一个MSIL生成器
            var IL = methodBuilder.GetILGenerator();
            // 开始编写方法的执行逻辑
            // var store = new string[3];
            var store = IL.DeclareLocal(typeof(string[]));
            IL.Emit(OpCodes.Ldc_I4, 3);
            IL.Emit(OpCodes.Newarr, typeof(string));
            IL.Emit(OpCodes.Stloc, store);
            //store[0] = "C"
            IL.Emit(OpCodes.Ldloc, store);
            IL.Emit(OpCodes.Ldc_I4, 0);
            IL.Emit(OpCodes.Ldstr, "C");
            IL.Emit(OpCodes.Stelem, typeof(string));
            //store[1] = "JAVA"
            IL.Emit(OpCodes.Ldloc, store);
            IL.Emit(OpCodes.Ldc_I4, 1);
            IL.Emit(OpCodes.Ldstr, "JAVA");
            IL.Emit(OpCodes.Stelem, typeof(string));
            //store[2] = "Python"
            IL.Emit(OpCodes.Ldloc, store);
            IL.Emit(OpCodes.Ldc_I4, 2);
            IL.Emit(OpCodes.Ldstr, "Python");
            IL.Emit(OpCodes.Stelem, typeof(string));
            // IChef chef = new GoodChef();
            var chef = IL.DeclareLocal(typeof(IChef));
            IL.Emit(OpCodes.Newobj, typeof(StoreChef).GetConstructor(Type.EmptyTypes));
            IL.Emit(OpCodes.Stloc, chef);
            //var dish = chef.Cook(vegetables);
            var dish = IL.DeclareLocal(typeof(string));
            IL.Emit(OpCodes.Ldloc, chef);
            IL.Emit(OpCodes.Ldloc, store);
            IL.Emit(OpCodes.Callvirt, typeof(IChef).GetMethod("Cook"));
            IL.Emit(OpCodes.Stloc, dish);
            // return dish;
            IL.Emit(OpCodes.Ldloc, dish);
            IL.Emit(OpCodes.Ret);
            //方法结束
            // 从类型构建器中创建出类型
            var dynamicType = tb.CreateType();
            // 通过反射创建出动态类型的实例
            var commander = Activator.CreateInstance(dynamicType);
            Console.WriteLine(dynamicType.GetMethod("Do").Invoke(commander, null).ToString());
            Console.ReadLine();
        }
    }
    public interface IChef
    {
        string Cook(string[] store);
    }
    public class StoreChef : IChef
    {
        public string Cook(string[] store)
        {
            return "Value:" + string.Join("+", store);
        }
    }
}


http://www.niftyadmin.cn/n/5199327.html

相关文章

MQTT协议消息代理服务远程连接

目录 1. Linux 搭建 Mosquitto 2. Linux 安装Cpolar 3. 创建MQTT服务公网连接地址 4. 客户端远程连接MQTT服务 5. 代码调用MQTT服务 6. 固定连接TCP公网地址 7. 固定地址连接测试 Mosquitto是一个开源的消息代理,它实现了MQTT协议版本3.1和3.1.1。它可以在不…

全球地表水年度数据集JRC Yearly Water Classification History, v1.4数据集

简介: JRC Yearly Water Classification History, v1.4是一个对全球水资源进行分类的数据集,覆盖了1984年至2019年的时间范围。该数据集是由欧盟联合研究中心(JRC)开发的,使用的数据源是来自Landsat系列卫星的高分辨率…

2023-11-20 LeetCode每日一题(最大子数组和)

2023-11-20每日一题 一、题目编号 53. 最大子数组和二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的…

腾讯云助力港华能源上线“碳汭星云2.0”,推动能源行业绿色低碳转型

11月17日,港华能源与腾讯云联合打造的港华智慧能源生态平台“碳汭星云2.0”升级上线。依托双方的连接、大数据能力和行业深耕经验,该平台打破了园区“数据孤岛”,进一步提升了数据治理、应用集成和复制推广能力,未来有望以综合能源…

SSM2

DataSource mybatis与Spring整合 事务加载业务层上面 开启事务驱动 上面都是声明式开启事务 图书管理系统 命名规范: java命名规范:驼峰命名法类:大驼峰变量,属性名.方法名:小驼峰 常量使用下划线分割:全大写,单词与单词之间下划线分割数据库命名规范:常用命名规范:下划线…

会议剪影 | 思腾合力受邀出席第四届长三角文博会并作主题演讲

以“担当新使命:长三角文化产业的力量”为主题的「第四届长三角国际文化产业博览会」于2023年11月16日-19日在国家会展中心(上海)成功举办。思腾合力作为行业领先的人工智能基础架构解决方案商出席本次盛会。 此次展会的面积首次超过10万平米&#xff0c…

单片非晶磁性测量系统典型磁参数的不确定度与重复性

典型磁参数的不确定度与重复性 典型的测试点 最佳不确定度 ( k 2 ) 最佳重复性 损耗Ps P1.0 ④ 3.0% 1.0% P1.3 3.0% 1.0% P1.4 3.0% 1.0% P1.5 3.0% 1.0% 磁感Bm B25 ⑤ 1.0% 0.3% B50 1.0% 0.3% B80 1.0% 0.3% 单片非晶磁性测量系统测量条件 &…

应用软件安全编程--24不要使用硬编码密匙

当程序中使用硬编码加密密匙时,所有项目开发人员都可以查看该密匙,甚至如果攻击者能够获取 程序 class文件,可通过反编译得到密匙,硬编码加密密匙会大大降低系统安全性。 对于避免使用硬编码密匙的情况,示例1给出了不…