.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

这篇具有很好参考价值的文章主要介绍了.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

上一篇介绍了 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 存储本地(变量)的简写。

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

.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

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

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

.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

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();

运行结果:

.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

方法原型对照:

.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

小说明:

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 指令方法:参数存储指令 

5、数组存储指令:Stelem、Stelem_Ref

当涉及到对数组进行赋值时,可使用该指令:

如果是值类型数组,用 Stelem 指令:

.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

 如果是引用类型数组,用 Stelem_Ref 指令:

.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

 该指令的使用示例,我们在下一篇章节创建数组对象指令中进行演示。

总结:

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

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

通过合理运用参数存储指令,我们可以实现更加高效、智能和灵活的动态代码生成过程。文章来源地址https://www.toymoban.com/news/detail-844120.html

到了这里,关于.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • .NET Emit 入门教程:第六部分:IL 指令:9:详解 ILGenerator 指令方法:运算操作指令(指令篇结束)

    经过前面几篇的学习,我们了解到指令的大概分类,如: 参数加载指令,该加载指令以 Ld 开头,将参数加载到栈中,以便于后续执行操作命令。 参数存储指令,其指令以 St 开头,将栈中的数据,存储到指定的变量中,以方便后续使用。 创建实例指令,其指令以 New 开头,

    2024年04月22日
    浏览(27)
  • .NET Emit 入门教程:第三部分:构建模块(Module)

    在这一部分中,我们将深入讨论动态程序集中模块的概念以及如何构建和管理模块。 模块是动态程序集中的基本单位,它类似于一个独立的代码单元,可以包含类型、方法、字段等成员。 在动态程序集中,模块扮演着组织代码和实现代码复用的关键角色。 它们允许开发人员

    2024年03月22日
    浏览(49)
  • .NET Emit 入门教程:第四部分:构建类型(Type)

    在动态生成代码的过程中,构建类型(Type)是至关重要的一步。 通过使用 Emit 中的 TypeBuilder,我们可以定义和创建各种类型,包括类、结构体和接口。 本节将深入探讨如何使用 TypeBuilder 动态构建类型,并介绍其在实际应用中的重要性。 通过学习本系列之前的文章,我们可

    2024年03月25日
    浏览(28)
  • .NET Emit 入门教程:第二部分:构建动态程序集(追加构建静态程序集教程)

    在本部分中,我们将深入探讨如何使用C# Emit 来创建动态程序集。 动态程序集是在运行时生成的,为我们提供了一种灵活、动态地构建和加载程序集的能力。 程序集是.NET中的基本部署单位,它包含了可执行代码、资源、元数据等信息,是.NET应用程序的基本组成单元之一。

    2024年03月21日
    浏览(35)
  • 【Git 入门教程】第六节、Git高级操作

    Git是一种非常强大的分布式版本控制系统,可以帮助开发者轻松地管理和协调代码库。在本文中,我们将介绍一些Git高级操作,包括如何管理Git仓库、标签、子模块和忽略文件。 Git提供了许多命令来管理本地Git仓库。以下是一些常用的管理命令: 初始化一个新的Git仓库: 查

    2024年02月05日
    浏览(40)
  • Odoo17入门教程第六章 UI

    现在我们已经创建了新模型及其 相应的,是时候了 与用户界面交互。 在本章结束时,我们将创建几个菜单以访问默认列表 和窗体视图。 参考 :与此主题相关的文档可以在数据文件中找到。 在第五章:安全性-简介中,我们通过 CSV 文件添加了数据。CSV 当要加载的数据具有

    2024年04月23日
    浏览(34)
  • 掌握Linux指令和权限:一个入门教程

    语法格式 :ls [选项][目录或者文件] 功能 :对于目录,该命令列出该目录下的所有子目录与文件。对于文件,将列出文件名以及其他信息。 a 列出目录下的所有文件,包括以 . 开头的隐含文件。 -d 将目录象文件一样显示,而不是显示其下的文件。 如:ls –d 指定目录 -i 输出文

    2023年04月23日
    浏览(29)
  • C语言快速入门教程1快速入门 2指令 3条件选择

    C是一种编程语言,1972年由Dennis Ritchie在美国AT T的贝尔实验室开发。C语言变得很流行,因为它很简单,很容易使用。今天经常听到的一个观点是--\\\"C语言已经被C++、Python和Java等语言所取代,所以今天何必再去学习C语言\\\"。我很不赞同这种观点。这有几个原因。这些原因如下:

    2024年02月03日
    浏览(34)
  • C语言入门教程,C语言学习教程(第三部分:C语言变量和数据类型)二

    前面我们多次提到了字符串,字符串是多个字符的集合,它们由 \\\" \\\" 包围,例如 \\\"http://c.biancheng.net\\\" 、 \\\"C语言中文网\\\" 。字符串中的字符在内存中按照次序、紧挨着排列,整个字符串占用一块连续的内存。 当然,字符串也可以只包含一个字符,例如 \\\"A\\\" 、 \\\"6\\\" ;不过为了操作方

    2024年01月17日
    浏览(40)
  • ESP8266-01s入门:上报和下发数据控制单片机 AT指令讲解和上云 烧录AT固件与OneNET MQTT通信教程包含MQTT.fx1.7.1教程(微信小程序通信单片机前置任务)

    本项目教程总共分为四节 1.创建OneNET新版MQTT设备:为微信小程序与单片机通信打基础(微信小程序通信单片机前置任务) 2.(当前文章)ESP8266-01s入门:烧录AT固件与OneNET MQTT通信教程包含MQTT.fx1.7.1教程(微信小程序通信单片机前置任务) 3.物联网实践教程:微信小程序结合

    2024年02月04日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包