Emit创建常见元素—自定义类型

Emit创建动态类 使用emit编写IL代码,在运行期创建实体类,不用在设计期创建实体。 立即下载

原文地址:http://www.cnblogs.com/MythYsJh/archive/2010/04/28/1723398.html

本文讲述用Emit创建枚举,结构体,类,接口等类型.

  同样,让我们先搭好大体框架:

            AssemblyName assemName  =   new  AssemblyName();
            assemName.Name 
=   " EmitStudy3 " ;

            AssemblyBuilder asmBuilder 
=
               AppDomain.CurrentDomain.DefineDynamicAssembly(assemName,
                  AssemblyBuilderAccess.RunAndSave);

            var mdlBldr 
=  asmBuilder.DefineDynamicModule( " EmitStudy3 " ,  " EmitStudy3.dll " );

            
// TODO:添加自定义类型

            asmBuilder.Save(
" EmitStudy3.dll " );

 

一、创建枚举

  枚举通过ModuleBuilder.DefineEnum来实现。

       var enumBldr  =  mdlBldr.DefineEnum( " Sex " , TypeAttributes.Public,  typeof ( int ));

 

  这里定义了一个基础类型为int,名称为Sex的public枚举。下面,让我们再为该枚举添加'内容':

            enumBldr.DefineLiteral( " Male " ,  0 );
            enumBldr.DefineLiteral(
" Female " ,  1 );

 

  之后也需要像创建类一样使用

            enumBldr.CreateType();

 

来完成一个枚举的创建。这是用Reflector查看就可以看到如下一个枚举了:

public   enum  Sex
{
    Male,
    Female
}

 

 

 

  二、结构体(struct)

  在ModuleBuilder中并不存在DefineStruct之类的方法。那该如何创建一个结构体呢?我们首先用C#创建一个结构体然后反编译成IL就会发现结构体实质是继承于ValueType的一个类。因此我们可以这样来创建一个结构体:

            var nameStruct  =  mdlBldr.DefineType( " Name " , TypeAttributes.Public,  typeof (ValueType));
            var fldFirstName 
=  nameStruct.DefineField( " FirstName " ,  typeof ( string ), FieldAttributes.Private);
            var fldLastName 
=  nameStruct.DefineField( " LastName " ,  typeof ( string ), FieldAttributes.Private);

            var methodGetFirstName 
=  nameStruct.DefineMethod( " GetFirstName " , MethodAttributes.Public, CallingConventions.Standard,  typeof ( string ),  null );
            var methodSetFirstName 
=  nameStruct.DefineMethod( " SetFirstName " , MethodAttributes.Public, CallingConventions.Standard,  null , new  []{  typeof ( string )});

            var ilGetFirstName 
=  methodGetFirstName.GetILGenerator();
            ilGetFirstName.Emit(OpCodes.Ldarg_0);
            ilGetFirstName.Emit(OpCodes.Ldfld, fldFirstName);
            ilGetFirstName.Emit(OpCodes.Ret);

            var ilSetFirstName 
=  methodSetFirstName.GetILGenerator();
            ilSetFirstName.Emit(OpCodes.Ldarg_0);
            ilSetFirstName.Emit(OpCodes.Ldarg_1);
            ilSetFirstName.Emit(OpCodes.Stfld, fldFirstName);
            ilSetFirstName.Emit(OpCodes.Ret);

            var prptFirstName 
=  nameStruct.DefineProperty( " FirstName " , PropertyAttributes.None,  typeof ( string ),  null );
            prptFirstName.SetGetMethod(methodGetFirstName);
            prptFirstName.SetSetMethod(methodSetFirstName);

            var methodGetLastName 
=  nameStruct.DefineMethod( " GetLastName " , MethodAttributes.Public, CallingConventions.Standard,  typeof ( string ),  null );
            var methodSetLastName 
=  nameStruct.DefineMethod( " SetLastName " , MethodAttributes.Public, CallingConventions.Standard,  null ,  new [] {  typeof ( string ) });

            var ilGetLastName 
=  methodGetLastName.GetILGenerator();
            ilGetLastName.Emit(OpCodes.Ldarg_0);
            ilGetLastName.Emit(OpCodes.Ldfld, fldLastName);
            ilGetLastName.Emit(OpCodes.Ret);

            var ilSetLastName 
=  methodSetLastName.GetILGenerator();
            ilSetLastName.Emit(OpCodes.Ldarg_0);
            ilSetLastName.Emit(OpCodes.Ldarg_1);
            ilSetLastName.Emit(OpCodes.Stfld, fldLastName);
            ilSetLastName.Emit(OpCodes.Ret);

            var prptLastName 
=  nameStruct.DefineProperty( " LastName " , PropertyAttributes.None,  typeof ( string ),  null );
            prptLastName.SetGetMethod(methodGetLastName);
            prptLastName.SetSetMethod(methodSetLastName);

            nameStruct.CreateType();

 

  上面就创建了一个包含FirstName和LastName的结构体Name。

  

  三、创建接口

  同样在ModuleBuilder中也没有DefineInterface这样的方法。而通过观察IL代码同样可以发现接口其实也是类。因此我们还是可以想创建类一样来创建接口.

            var iStudentBldr  =  mdlBldr.DefineType( " IStudent " , TypeAttributes.Public |  TypeAttributes.Interface  |  TypeAttributes.Abstract,  null );
            iStudentBldr.DefineMethod(
" Update " , MethodAttributes.Virtual  |  MethodAttributes.Abstract,  null ,  null );
            iStudentBldr.CreateType();

 

这样就创建了一个仅包含一个Update方法的接口IStudent。在创建接口时也要注意TypeAttributes需声明为 TypeAttributes.Interface | TypeAttributes.Abstract,而接口包含的方法的MethodAttributes则必须为MethodAttributes.Virtual | MethodAttributes.Abstract。

  

  四、创建类

  已经有很多这方面的例子,这里就不再赘述。

 

  五、委托和事件

  老规矩,从反编译的IL代码入手。可以发现我们创建的委托其实是派生自MultiDelegate类的类。而MultiDelegate这个类比较特殊,它不能从C#代码里被继承,但在IL代码却可以。因此可以如下来定义委托。

            var delPropertyChangedHandler  =  mdlBldr.DefineType( " PropertyChanedHandler " , TypeAttributes.Public,  typeof (MulticastDelegate));
            delPropertyChangedHandler.CreateType();

 

  但是这样的定义似乎总觉得很奇怪,因为委托还包含返回值及参数等信息,这些在这段代码都没有得到体现。那么该如何创建委托呢?让我们还是从现有的入手,以EventHandler为例,在Reflector下它的结构为

     

      事实上,创建委托必须包含一个构造函数和Invoke方法。Invoke方法的参数则是委托的参数,返回类型即为委托的返回类型。

            var delPropertyChangedHandler  =  mdlBldr.DefineType( " PropertyChanedHandler " , TypeAttributes.Public  |  TypeAttributes.Sealed,  typeof (MulticastDelegate));
            var constructor 
=  delPropertyChangedHandler.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard,  new [] {  typeof ( object ),  typeof (IntPtr) });
            constructor.SetImplementationFlags(MethodImplAttributes.Runtime 
|  MethodImplAttributes.Managed);

            var methodInvoke 
=  delPropertyChangedHandler.DefineMethod( " Invoke " , MethodAttributes.Public  |  MethodAttributes.Virtual,  null ,  new [] {  typeof ( string ) });
            methodInvoke.SetImplementationFlags(MethodImplAttributes.Managed 
|  MethodImplAttributes.Runtime);

            var delType = delPropertyChangedHandler.CreateType();

 

构造函数和Invoke方法都使用了SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime),因为二者的方法体是在运行时才能决定的。

       既然已经创建了委托,让我们再用此委托添加一个事件。定义事件就相对容易些了,直接使用TypeBuilder.DefineEvent即可.

          var typeBldr  =  mdlBldr.DefineType( " Sdudent " , TypeAttributes.Public);
          
// 其余部分
          typeBldr.DefineEvent( " OnNameChanged " , EventAttributes.None, delType);
          typeBldr.CreateType();

 

 

六、小结

      我们已经可以用Emit创建常见元素了。当然,Emit还可以创建很多其他内容,不可能介绍完全,关键是要掌握通过C#和IL对比来完成Emit的基本方法。这样,我们就基本可以解决遇到的大部分问题了。欢迎大家指正。

HUMAnN数据库国内备份下载源(转自刘永鑫博士github) 百度云链接 R语言常用包合集 Windows 10版4.0.x:链接:https://pan.baidu.com/s/1JFwLP2SonK1howD5MNgNYg 提取码:l08k Windows 10版3.6.x:链接:https://pan.baidu.com/s/1h-qR2lmlaMgR4M7VbgtAFg 提取码:s5fi 下载后解压至当前目录,可获得3.6/4.0目录,剪切并替换文档 - R - win-library - 3.6/4.0 目录即可 扩增子数据库 宏基因组数据库 HUM. 阅读详情

相关推荐

robomimic实验复现全流程:从数据集下载到训练视频生成

本文详细介绍了机器人模仿学习项目RoboMimic的完整实验复现流程。内容涵盖从使用Conda创建Python 3.8隔离环境、安装RoboSuite仿真器和MuJoCo物理引擎,到下载并探索数据集、配置与启动模型训练,最后进行模型评估和生成策略执行视频。该指南旨在帮助研究者和开发者高效搭建实战环境,规避常见问题,快速验证算法或应用于实际场景。

weixin_29089057的博客 518

【通过 emit() 触发的​​自定义事件】

[TOC](通过 emit() 触发的​​自定义事件​​)

m0_52150489的博客 182

three.js 载入 3D 模型的方法

三维模型的加载器ColladaLoader模型加载器。GLTFLoader模型加载器。OBJLoader模型加载器。FBXLoader模型加载器。

w418856的博客 4362

QT 之 emit 自定义信号

Qt 的信号与槽机制是一种用于对象间通信的核心特性,特别适用于 GUI 编程。信号与槽提供了一种松耦合的方式来响应事件。信号:信号是对象中用来表示某些事件的成员。当某个特定事件发生时,信号会被触发。槽:槽是一个普通的成员函数,用于处理信号。当信号被触发时,槽会被调用。连接:连接是将信号与槽关联起来的操作。自定义信号与槽通常用于需要在自定义类中发射信号并处理特定事件的情况。步骤定义一个包含信号与槽的类,并继承QObject。使用signals关键字定义信号。使用slots关键字定义槽。使用。

m0_63485514的博客 972

ROS2实战:打造智能巡检机器人的关键技术与实现

本文详细介绍了基于ROS2和Navigation2构建智能巡检机器人的完整实战流程。通过设计主从协作的事件驱动架构,实现了机器人在已知地图中的自动导航、定点语音播报和环境图像采集功能。文章涵盖了从环境搭建、仿真配置到核心控制节点、语音服务与图像记录模块的代码实现,为开发者打造实用的自动巡检机器人提供了清晰的技术指南。

weixin_29031057的博客 223

2026年AI技能进阶指南:从提示词工程到智能体开发实战

提示词工程作为AI时代的基础沟通技能,其核心原理是通过系统化的交互方法论实现与大模型的高效对话。这项技术通过明确性、具体性和可操作性的设计原则,显著提升了AI生成内容的质量和实用性。在工程实践层面,提示词工程已经发展出角色扮演、步骤分解等成熟模式,广泛应用于代码生成、技术方案设计等场景。随着AI智能体开发的兴起,提示词工程进一步演化为定义智能体身份认知和行为规范的系统接口设计,成为构建自主AI系统的关键技术基础。掌握从基础提示词到智能体开发的完整技能栈,能够帮助开发者在AI技术浪潮中保持核心竞争力。

weixin_33139275的博客 333

使用Emit的时候类型XXX尚未完成

Type t=[AssemblyBUilder].DefineType(XXXXX);t.CreateType();当时看msdn示例的时候代码非常的冗长,在茫茫代码中没发现第二句话,真是无辜啊。

weixin_34208185的博客 252

LDPC码介绍:基础&编码&译码

本博客介绍了LDPC码的基本原理,其中包括校验矩阵的构造、Tanner 图和编译码的基础知识。

渺小的颗星的博客 4309

EMIT 动态创建类型

https://www.cnblogs.com/xiaodlll/p/4029051.html  值得一读

weixin_34327761的博客 379

基于PSINS的INS/NHC/ODO组合导航仿真全解析

组合导航通过多传感器融合克服单一导航系统的局限,是车辆自主定位的关键技术。其中惯性导航(INS)依靠陀螺仪与加速度计积分推算运动状态,但误差随时间累积;GNSS提供绝对位置,却在城市峡谷中易受多径效应和遮挡影响导致定位漂移。卡尔曼滤波作为信息融合核心,将不同量测按统计特性加权,实现优势互补。基于PSINS开源工具箱搭建的SINS/GNSS/ODO/NHC组合导航仿真,能够在GNSS失锁条件下利用非完整约束和里程计抑制惯性误差发散,广泛应用于无人驾驶、物流车辆自主定位等场景。本文围绕PSINS仿真环境,详细拆

weixin_29044713的博客 253

10分钟搞定小红书爆款笔记爬取!Selenium模拟登录+数据解析全流程,新手也能落地

小红书爬虫实战的核心,是**“模拟真人操作+解析结构化数据”**——Selenium解决了动态页面和登录的问题,lxml解决了数据提取的问题,pandas解决了数据存储的问题。新手学爬虫不用一开始就啃复杂的反爬机制,先从这类“可见即可爬”的场景入手,掌握“模拟操作→数据解析→数据保存”的全流程,再逐步叠加异常处理、批量爬取、反爬应对等功能。需要注意的是:爬取数据仅用于个人学习和研究,不得用于商业用途,且需遵守小红书的用户协议,不要过度爬取导致服务器压力。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1729

.NET Emit 入门教程:第一部分:Emit 介绍:什么是 Emit

在.NET开发中,Emit 是一种动态生成IL代码的技术,通过使用 System.Reflection.Emit 命名空间中的类,可以在运行时创建和修改程序集、类型和方法。这种技术为开发人员提供了一种强大的方式来在运行时动态生成和执行代码:Emit 技术通常用于解决需要在运行时动态生成代码的特定场景,例如在ORM(对象关系映射)框架中动态创建实体类,或者在AOP(面向切面编程)中动态创建代理类。

路过秋天 - 理想很美好,现实很残酷,坚持在路上,只因初心仍存 1535

ESP32-C3入门教程 蓝牙篇①——基于Blufi 的 WiFi 智能配网

文章目录一、前言二、WiFi配网方式三、快速运行四、运行效果五、ESP32-C3程序流程5.1 主程序5.2 回调函数5.3 SmartConfig线程5.4 流程图六、关键函数6.1 设置SmartConfig的协议类型6.2 启动SmartConfig6.3 停止SmartConfig七、其他八、参考 一、前言 本文基于VS Code IDE进行编程、编译、下载、运行等操作 基础知识点请查阅:ESP32-C3入门教程 基础篇①——基于VS Code构建Hello World 二、WiFi配网方式 W

7765

QT中的emit关键字

在QT中的emit使用方法,将文本使用emit关键字发送到label上面更改界面内容

qq_56589253的博客 5968

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

反射发出--Emit

"反射"和"放射发出(Emit)"的关系 相信反射大家都不陌生,我也曾写过关于反射的文章,大家有兴趣可以看看,但是今天要说的不是"反射"而是"反射发出(Emit)"。我们知道反射的主要功能是获得对象的信息、调用对象的方法等;而反射发出的主要功能是动态的创建对象。那么是不是二者就没有关系呢?事实上二者不经有关系而且关系十分密切。从命名空间我们就可以看出来,反射处于命名空间下,而反射发出Emit处于命名空间下,它的功能虽然主要是动态创建对象,但是很多反射能够完成的工作它也可以完成而且速度更快(实现当然较反射而

Kenshin Cui's Blog 4970

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C# Emit技术详解

C# 中的 Emit 技术是一种强大的元编程(metaprogramming)技术,允许您在运行时生成和动态修改 C# 代码。这种技术通常用于创建动态生成的程序集、实现 AOP(面向切面编程)、序列化对象、创建动态代理等场景。它是通过 System.Reflection.Emit 命名空间中的类来实现的。

极客神殿 1518

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

详解c# Emit技术

我们常常有一个应用场景,由我们的C#代码,动态生成一个EXE,其应用场景可以非常多,比如软件授权,可以输入授权信息后,生成一个授权的DLL等,那如何实现这个功能呢,就要提到一个技术Emit。 1、Emit概述 Emit,可以称为发出或者产生。在Framework中,与Emit相关的类基本都存在于System.Reflection.Emit命名 空间下。可见Emit是作为反射的一个元素存在的。说道反射,大家应该都不陌生,它允许我们查看程序集的元素据,从而取得形如程序集包含哪些类型,类型包 含哪些方法等等大量的

chinaherolts2008的博客 2544

DefineModel可以传递方法的特性对emit的影响

虽然在 Vue 3 中大大简化了双向绑定的实现,使得双向绑定的事件处理更加自动化和高效,但这并不意味着emit会变得可有可无。emit仍然在 Vue 中扮演着重要角色,尤其是在处理复杂事件、多种自定义事件以及其他非双向绑定的场景时。和emit作为 Vue 中两种不同的机制,各自有着明确的用途和适用范围,开发者应根据实际需求灵活选择使用。简化了双向绑定,但emit依然是 Vue 事件驱动架构的核心部分,无法完全被替代。

百锦再的博客 3799

Emit学习(1)-Emit概览

原文:http://www.csharpwin.com/csharpspace/10973r3457.shtml 一、Emit概述   Emit,可以称为发出或者产生。在Framework中,与Emit相关的类基本都存在于System.Reflection.Emit命名空间下。可见Emit是作为反射的一个元素存在的。说道反射,大家应该都不陌生,它允许我们查看程序集的元素据,从而取得形如

每天进步一点点 1429

EMIT-Data-Resources 项目使用教程

EMIT-Data-Resources 项目使用教程 1. 项目介绍 EMIT-Data-Resources 是由 NASA 开发的开源项目,旨在帮助用户访问和处理来自地球表面矿物尘埃源调查(EMIT)任务的数据。EMIT 项目通过国际空间站(ISS)上的测量,提供地球干旱尘埃源区域的表面矿物学数据。这些数据用于初始化地球系统模型(ESMs)中的尘埃源组成,从而更好地理解尘埃循环及其对地球系统的影...

gitblog_00581的博客 781

Reflection Emit(创建类步骤)

1.什么是的反射发出(Reflection Emit)System..Reflection.Emit命名空间嵌套在System.Reflection的下面,它可动态的构建程序集和类型的所有框架类的根,在需要时动态的产生代码。注意:反射发出(reflection emit)并不能产生源代码。换句话说,你在这里的努力并不能创建VB.Net或者C#代码。相反,反射发出(reflection e...

aikk20319的博客 281

Emit学习之旅(2):创建常见元素—基础部分

上回已经用Emit创建了一个简单的类型。下面接着说说如何为动态创建的类添加实例成员,属性,方法等。 准备工作      这次来创建一个Student类。首先准备好大致框架: AssemblyName assemName = new AssemblyName(); assemName.Name = "EmitStudy2"; As...

sunct的博客 210

java中emit的用法_Java中通过Emit实现动态类生成

Java中通过Emit实现动态类生成2007-6-10文字大小:大中小动态生成一个类对于AOP,O/R Mapping等技术非常有帮助。对于Java来说,问题不大,而对于.NET,则要麻烦些(主要麻烦在于实现代码的生成需要IL),故猜测这可能也是在AOP, O/R Mapping方面,Java走得略前的原因吧。麻烦归麻烦,非不能也,动态生成一个简单的类还不至于太难。假设有如下接口:interfac...

weixin_35654499的博客 833

Emit 学习之旅(1) ----Emit 概述

一、Emit 概述         Emit可以称为发出或者产生

mounting的专栏 1077

反射的Emit实现

反射的 Emit实现 在日常开发中,我们频繁用到反射,除了最“繁重”的原始反射方式(这里不讲解),以及 4.0的关键字dynamic,还有许多的方式(Emit以及Linq)。接下来的演示,我将着重对以下这个类进行操作。 publicclassUser { publicstringUsername{get;set;} } ...

weixin_33955681的博客 299

此处的memory与emit是什么

当合约发生重要事情(比如有人存钱),它通过广播喇叭(事件)通知所有人:“注意!关键字用于触发一个事件,事件的参数会被记录到区块链的交易日志中,供外部程序(如前端应用)监听。是用于不同目的的关键字,下面通过通俗易懂的方式解释它们的作用,并结合你的代码示例说明。你在草稿纸上写写画画(处理数据),用完就丢(不保存到区块链),成本低且灵活。:前端应用可以通过监听事件实时感知合约状态变化(如新请求创建、转账完成)。:触发事件,向外部世界广播关键操作(如状态变更)。事件,实时获取新请求的索引(例如更新 UI)。

小宝哥Code的专栏 1098
上一篇: Visual ILMerge
下一篇: 使用SqlDependency时提示当前数据库未启用Service broker
andycode
博客等级 码龄17年 12粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值