前言:

上上篇介绍了 IL 指令的分类以及参数加载指令,该加载指令以 Ld 开头,将参数加载到栈中,以便于后续执行操作命令。

上一篇介绍参数存储指令,其指令以 St 开头,将栈中的数据,存储到指定的变量中,以方便后续使用。

本篇将介绍创建实例指令,其指令以 New 开头,用于在运行时动态生成并初始化对象。

创建实例指令简介

在.NET Emit 中,使用 ILGenerator 创建实例是一项重要的操作,它允许我们动态生成对象实例和数组实例的代码。

通过创建实例指令,我们可以在运行时动态生成并初始化对象,为程序提供更大的灵活性和可扩展性。

创建实例指令主要包括 Newobj 指令和 Newarr 指令。

Newobj 指令用于创建新的对象实例,而 Newarr 指令则用于创建新的数组实例。

这些指令的灵活运用可以帮助我们在运行时动态地生成各种类型的实例,满足不同场景下的需求。

在本篇文章中,我们将深入探讨 ILGenerator 中的创建实例指令,详细解析其用法和示例代码。

通过学习本文内容,读者将能够掌握如何利用 ILGenerator 创建对象实例和数组实例,从而更好地理解和应用.NET Emit 技术。

1、创建实例指令:Newobj

对于该指令,其核心在于如何获取构造函数并作为参数传递,下面看一组示例。

共用代码,定义实体(包含无参构造函数、有参构造函数、基本变量):

 public class Entity
{
public Entity()
{ }
public Entity(int id)
{
this.ID = id;
}
public int ID;
}

共用代码,生成程序集,以方便后续对照参考:

AssemblyName assName = new AssemblyName("myAssembly") { Version = new Version("1.1.1.2") };
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule("myModule", "b.dll");
TypeBuilder tb = mb.DefineType("MyNameSpace.MyClass", TypeAttributes.Public | TypeAttributes.Class); //定义静态方法
MethodBuilder methodBuilder = tb.DefineMethod("NewObj", MethodAttributes.Public | MethodAttributes.Static, typeof(Entity), new Type[] { });
ILGenerator il = methodBuilder.GetILGenerator(); //il 代码处...... Type classType = tb.CreateType(); ab.Save("b.dll");

A、无参数实例化:通过 Type 的 GetConstructor 实例方法获取类型的构造函数。

ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Ret); // 返回该值

对照生成:

B、使用参数实例化:

 ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldc_I4, 999);
il.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(int) }, null));
il.Emit(OpCodes.Ret); // 返回该值

对照生成:

小说明:

这里构造函数的参数传入,是通过 Ld 系列指令按顺序压入栈中。

2、创建实例指令:Newarr

该指令用于创建数组对象,该指令需要指定数组长度。

A、创建数组:

ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldc_I4, 6);
il.Emit(OpCodes.Newarr, typeof(Entity));
il.Emit(OpCodes.Ret); // 返回该值

对照生成代码:

小说明:

Newarr 接收的参数,是 Type 类型。

Newobj 接收的参数,是 ConstructorInfo 构造函数类型。

B、对数组赋值:引用类型

ILGenerator il = methodBuilder.GetILGenerator();

//创建数组
il.Emit(OpCodes.Ldc_I4, 3);
il.Emit(OpCodes.Newarr, typeof(Entity)); il.DeclareLocal(typeof(Entity[]));
il.DeclareLocal(typeof(Entity));
il.Emit(OpCodes.Stloc_0);//存储数组 for (int i = 0; i < 3; i++)
{
il.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));//定义实体类
il.Emit(OpCodes.Stloc_1);//存储实体类 il.Emit(OpCodes.Ldloc_0);//加载数组
il.Emit(OpCodes.Ldc_I4, i);//加载索引
il.Emit(OpCodes.Ldloc_1);//加载Entity il.Emit(OpCodes.Stelem_Ref);//引用类型赋值
} il.Emit(OpCodes.Ldloc_0);//加载数组
il.Emit(OpCodes.Ret); // 返回该值

对照生成代码:

C、对数组赋值:值类型

ILGenerator il = methodBuilder.GetILGenerator();

//创建数组
il.Emit(OpCodes.Ldc_I4, 3);
il.Emit(OpCodes.Newarr, typeof(DateTime)); il.DeclareLocal(typeof(DateTime[]));
il.DeclareLocal(typeof(DateTime));
il.Emit(OpCodes.Stloc_0); for (int i = 0; i < 3; i++)
{// 调用 DateTime.Parse 方法创建 DateTime 实例
MethodInfo parseMethod = typeof(DateTime).GetMethod("Parse", new Type[] { typeof(string) });
il.Emit(OpCodes.Ldstr, DateTime.Now.ToString()); // 传递当前时间字符串
il.Emit(OpCodes.Call, parseMethod); // 调用 Parse 方法
il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Ldloc_0);//加载数组
il.Emit(OpCodes.Ldc_I4, i);//加载索引
il.Emit(OpCodes.Ldloc_1);//加载Entity il.Emit(OpCodes.Stelem, typeof(DateTime));//赋值
} il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret); // 返回该值

对照生成代码:

D、数组取值指令:

总结:

在.NET Emit 入门教程的第六部分中,我们深入探讨了 ILGenerator 指令方法,特别是关于创建实例指令的详细解释。

ILGenerator 是.NET框架中的一个强大工具,用于在运行时生成和执行IL代码。

在这篇文章中,我们学习了如何使用 ILGenerator 来创建实例,其中主要涉及到了两种指令方法:newobj 和 newarr。

通过 newobj 指令,我们可以在IL代码中调用构造函数来创建类的实例,而 newarr 指令则用于创建数组实例。

通过学习这些内容,读者可以更深入地理解 ILGenerator 的使用,并在实际项目中应用动态代码生成的技术。

下一篇,我们将学习方法调用指令的相关内容。

.NET Emit 入门教程:第六部分:IL 指令:5:详解 ILGenerator 指令方法:创建实例指令的更多相关文章

  1. Golang入门教程(十三)延迟函数defer详解

    前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...

  2. Docker入门教程(六)另外的15个Docker命令

    Docker入门教程(六)另外的15个Docker命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第六篇,继续介绍Docker命令.之前的第二篇文章 ...

  3. 无废话ExtJs 入门教程十六[页面布局:Layout]

    无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...

  4. Photoshop入门教程(六):通道

    学习心得:当大部分人听到通道.心里可能会有一种很害怕的感觉,因为“通道”并不像“图层”这样易于理解,望而生畏.”通道“的本质其实是存储图片的信息,把一张图片比作一个为网站,那么通道就是网站的后台,存储 ...

  5. RabbitMQ入门教程(十六):RabbitMQ与Spring集成

    原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...

  6. ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解

    原文 ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 ...

  7. SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解

    SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解 博客分类: 跟开涛学SpringMVC   6.6.2.@RequestParam绑定单个请求参数值 @RequestParam用于 ...

  8. 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权

    原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...

  9. SaltStack 入门到精通第二篇:Salt-master配置文件详解

    SaltStack 入门到精通第二篇:Salt-master配置文件详解     转自(coocla):http://blog.coocla.org/301.html 原本想要重新翻译salt-mas ...

  10. 【入门】广电行业DNS、DHCP解决方案详解(三)——DNS部署架构及案

    [入门]广电行业DNS.DHCP解决方案详解(三)——DNS部署架构及案 DNS系统部署架构 宽带业务DNS架构 互动业务DNS架构 案例介绍 案例一 案例二 本篇我们将先介绍DNS系统部署架构体系, ...

随机推荐

  1. locals和globals,函数的嵌套,nonlocal,闭包函数及特点以及匿名函数---day11

    1.locals和globals 1.1locals  获取当前作用域中的所有内容 locals 如果在函数外,调用locals(),获取打印的是打印之前的所有变量,返回字典,全局空间作用域 loca ...

  2. Linux查看文件大小、磁盘使用情况

    1.显示磁盘的可用情况: df -h 2.显示文件夹大小 du -ka folder | sort -rnk 1 | head -n 10

  3. 【Azure 环境】移动应用 SSO 登录AAD, MSAL的配置为Webview模式时登录页面无法加载

    问题描述 移动端集成MASL登录过程中,配置文件中配置项"authorization_user_agent"使用"DEFAULT"可以正常登录,但是改为&quo ...

  4. 【Azure 环境】Update-MgEntitlementManagementAccessPackageAssignmentPolicy 命令执行时候遇见的 No HTTP Resource was found 问题分析

    Microsoft Graph PowerShell SDK: acts as an API wrapper for the Microsoft Graph APIs, exposing the en ...

  5. markdown 一键上传发布

    工具介绍 工具由来 对于程序员等常常需要写文档的人来说,将本地markdown文档同步到云端博客平台,是一件比较繁琐的事情,首当其冲的是,大量的本地图片需要"互联网"化,即使网络上 ...

  6. autohotkey 设置快捷键 设置光标位置 (ctrl + alt + Numpad0)

    autohotkey 设置快捷键 设置光标位置 (ctrl + alt + Numpad0) 原因 3个屏幕,所以鼠标设置的灵敏度非常高,经常就找不到鼠标在哪了. 设置个快捷键,让鼠标每次都初始化一个 ...

  7. isNumber 数字正则校验 表达式

    isNumber 数字正则校验 表达式 isNumber(value) { return (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)|(^-?0{1}$)/).t ...

  8. vue中setTimeout之前 一定要 clearTimeout 否则将失效

    window.clearTimeout(this.singleClick) // 这句很重要,否则不起作用 this.singleClick = window.setTimeout(() => ...

  9. Python使用os模块创建带时间戳的文件

    直接上源码: import os import time # 定义函数名:在py文件路径下创建cache的txt文件 def txt(name, text): # os.getcwd() 获取当前的工 ...

  10. 【stars-one】B站视频下载通

    一键下载B站的普通视频.番剧.电影的小工具 获取软件 由于软件还未完善,目前打赏价定位5.88元,后面软件完善价格会提高 >>>点击跳转打赏页面 目前Android版还在开发中 电脑 ...