前言:

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

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

参数存储指令介绍:

在 IL 中,除了参数存储指令 stargstloc 之外,还有其他一些以 "st" 开头的指令,如 stfldstsfld,它们也用于存储值到特定位置。以下是所有的参数存储指令以及它们的用途:

  1. starg index:将计算堆栈顶部的值存储到方法的参数中,参数索引由后续字节指定。

  2. stloc index:将计算堆栈顶部的值存储到方法的局部变量中,局部变量索引由后续字节指定。

  3. stfld field:将计算堆栈顶部的值存储到对象的字段中,字段由元数据标识指定。

  4. stsfld field:用于将值存储到静态字段(static field)中。静态字段是属于类本身而不是类的实例的字段,它们在整个应用程序生命周期内只有一份拷贝,被所有实例共享。

这些指令都是用于在 IL 中进行值的存储操作,用途包括更新方法参数、修改局部变量值、设置对象字段值以及修改数组元素。它们在方法体中起到了关键的作用,用于实现各种数据操作和赋值操作。

1、存储指令:starg

  1. starg.s index:将计算堆栈顶部的值存储到方法的参数中,参数索引由单字节指定(适用于参数索引小于 256 的情况)。

  2. starg index:将计算堆栈顶部的值存储到方法的参数中,参数索引由后续字节指定(适用于参数索引大于等于 256 的情况)。

该指令为:store argument 存储参数的简写。

示例代码:

var dynamicMethod = new DynamicMethod("GetValue", typeof(object), new[] { typeof(string) }, typeof(AssMethodIL_ST));

var ilGen = dynamicMethod.GetILGenerator();

// 使用 starg 指令将方法参数值传递给局部变量
ilGen.Emit(OpCodes.Ldstr,"abc");
ilGen.Emit(OpCodes.Starg, 0); // 将方法的第一个参数值传递给局部变量 // 返回局部变量的值
ilGen.Emit(OpCodes.Ldarg_0); // 加载第一个参数(message)
ilGen.Emit(OpCodes.Ret); // 返回该值

该示例的代码,主要体现在对参数重新赋值,对应的方法原型:

public static object GetValue(string arg)
{
arg = "abc";
return arg;
}

2、存储指令:stloc

stloc index:将计算堆栈顶部的值存储到方法的局部变量中,局部变量索引由后续字节指定。

该指令为:store local 存储本地(变量)的简写。

该方法需要配合辅助变量使用,这个在上一篇辅助方法中有介绍到,这里重温一下上上篇的辅助方法,定义变量的内容:

该系列指令中,还有stloc_0、stloc_1、stloc_2、stloc_3,代表定义的第N个临时变量。

该变量的定义在反编绎 IL 中可以对照 .locals init 内容:

3、存储指令:stfld

stfld field:将计算堆栈顶部的值存储到对象的字段中,字段由元数据标识指定。

该参数为:store filed 存储字段的简写,其常用于给字段变量赋值。

下面举一个给成员变量赋值的示例:

Entity entity = new Entity();

FieldInfo idInfo = typeof(Entity).GetField("ID");

var dynamicMethod = new DynamicMethod("SetValue", typeof(void), new[] { typeof(Entity), typeof(int) }, typeof(AssMethodIL_ST));

var ilGen = dynamicMethod.GetILGenerator();

ilGen.DeclareLocal(typeof(Entity));

ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldarg_1);
ilGen.Emit(OpCodes.Stfld, idInfo);
ilGen.Emit(OpCodes.Ret); dynamicMethod.Invoke(null, new object[] { entity, 111 }); Console.WriteLine(entity.ID);
Console.Read();

运行结果:

方法原型对照:

小说明:

stfld 指令是成员变量的赋值,而我们常用的属性赋值【get】或取值【set】,对应的是方法调用,因此属性的相关操作会在方法调用指令一文中再述。

4、存储指令:stsfld

该参数为:store static filed 存储静态字段的简写,其常用于给静态字段变量赋值。

示例代码:

public class Entity { public int ID; public static int ID2; }
public static void D3()
{
Entity entity = new Entity(); FieldInfo idInfo = typeof(Entity).GetField("ID2", BindingFlags.Static| BindingFlags.Public); var dynamicMethod = new DynamicMethod("SetValue", typeof(void), new[] { typeof(int) }, typeof(AssMethodIL_ST)); var ilGen = dynamicMethod.GetILGenerator(); ilGen.DeclareLocal(typeof(Entity)); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Stsfld, idInfo); // 加载第一个参数(message)
ilGen.Emit(OpCodes.Ret); // 返回该值 dynamicMethod.Invoke(null, new object[] { 222 }); Console.WriteLine(Entity.ID2);
Console.Read();
}

运行结果:

总结:

相比于参数加载指令的类型复杂度,参数存储指令则相对简约许多。

总的来说,参数存储指令的重要性在于它为动态生成代码提供了强大的参数处理能力,让开发者可以更加灵活地操作方法的参数,实现更加复杂和多样化的编程逻辑。

通过合理运用参数存储指令,我们可以实现更加高效、智能和灵活的动态代码生成过程。

.NET Emit 入门教程:第六部分:IL 指令:4:详解 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. centos7 安装vmware tool 遇到遇到 kernel-headers 问题修复

    安装 vmware tool 步骤 1. cp VMwareTools-10.3.25-20206839.tar.gz 到 用户目录下 2. tar zxf VMwareTools-10.3.25-2 ...

  2. 解决pip install时出现的Could not fetch URL https://pypi.org/simple/pip/问题

    打开windows的我的电脑,在最上方目录栏输入%APPDATA%,回车,接着会定位到一个新的目录, 目录路径为C:\Users\Administrator\AppData\Roaming,在这个目录 ...

  3. 【Docker】使用 Docker 部署 .Net Core 项目 (四)

    系列目录: [Docker] CentOS7 安装 Docker 及其使用方法 ( 一 ) [Docker] 使用Docker 在阿里云 Centos7 部署 MySQL 和 Redis (二) [D ...

  4. Excel 求和函数结果一直为零

    参考资料:Excel表格求和结果总是0怎么办 用SUMIFS函数求和,结果都是零 错误原因: 1.单元列数据格式设置错误,参考资料一 2.数据中含有空格或者回车键或者隐藏字符,参考资料二 解决方法: ...

  5. 好用网址分享-77ai导航与77搜索导航

    AI(人工智能)技术正在改变我们的生活方式和工作方式,越来越多的人开始关注和使用AI相关的网站和应用程序.在这篇文章中,我将为大家介绍一些常用的AI网址导航,帮助您更好地了解和使用AI技术. AI H ...

  6. Visual Studio部署C++环境下OpenCV库

      本文介绍在Visual Studio 2022中配置.编译C++计算机视觉库OpenCV的方法. 1 OpenCV库配置   首先,我们进行OpenCV库的下载与安装.作为一个开源的库,我们直接在 ...

  7. 18 Codeforces Round 853 (Div. 2)C. Serval and Toxel's Arrays(算贡献)

    C. Serval and Toxel's Arrays 这种题目做多了应该很容易从贡献的角度去考虑了. 考虑当前版本对答案的贡献,首先这个版本和其他版本取交集至少会包含它本身所以直接先把\(i * ...

  8. java线程示例

    需要开启线程 的方法继承线程类,并在run  中写逻辑 public class Ant extends Thread{ Cake cake; public Ant(String name,Cake ...

  9. Spring整合mybatis使用xml配置事务

    自己准备开始教授Java相关的技术,Spring框架是必须让学生学习的框架之一.里面有一个事务相关的 配置,以前刚学习Spring框架的时候有接触过,只是过了很多年,很多东西都已经淡忘.再来回忆一下 ...

  10. 协议I2C

    SCL   SDA   同步,半双工 开漏+弱上拉,谁用这跟线,就下拉成低电平 想输出,去拉杆子或放手,操作杆子变化 想输入,直接放手,看电平高低就行 线与,一个低电平,全部低电平,可以利用这个执行多 ...