前言:

经过前面几篇的学习,我们了解到指令的大概分类,如:

参数加载指令,该加载指令以 Ld 开头,将参数加载到栈中,以便于后续执行操作命令。

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

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

方法调用指令,该指令以 Call 开头,用于在运行时调用其它方法。

支条件指令,该指令通常以 Br、或 B、C 开头,用于在运行分支条件时跳转指令。

本篇介绍类型转换指令,该指令通常以 Cast、Conv 开头或box结尾,用于在运行时对类型进行转换。

类型转换指令介绍:

在.NET中,类型转换是一个常见的操作,它允许我们在不同的数据类型之间进行转换。ILGenerator 提供了一系列的指令来执行各种类型转换操作。这些指令可以分为三类:强制类型转换指令、隐式类型转换指令和数值类型转换指令。

  1. 强制类型转换指令:这些指令用于执行显式的类型转换操作,如果转换失败则会抛出异常。常见的强制类型转换指令包括 castclass 和 isinst 指令。

  2. 隐式类型转换指令:这些指令用于执行从引用类型到值类型或者从值类型到引用类型的转换,或者在值类型之间执行转换。unboxbox 指令是常见的隐式类型转换指令。

  3. 数值类型转换指令:这些指令用于执行不同数值类型之间的转换,比如将整数转换为浮点数,或者将浮点数转换为整数。conv 指令系列提供了这些功能。

通过这些类型转换指令,我们可以在 IL 级别执行各种类型转换操作,为动态生成的代码增加了灵活性和功能性。

接下来我们将详细介绍这些指令的用法和示例。

1、强制类型转换指令:

Castclass 指令:强制类型转换

示例代码:

MethodBuilder methodBuilder = tb.DefineMethod("ConvertTo", MethodAttributes.Public | MethodAttributes.Static, typeof(XmlEntity), new Type[] { typeof(object) });

ILGenerator il = methodBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg_0 );
il.Emit(OpCodes.Castclass, typeof(XmlEntity)); il.Emit(OpCodes.Ret); // 返回该值

对应代码:

Isinst 指令: as 类型转换

示例代码:

MethodBuilder methodBuilder = tb.DefineMethod("ConvertTo", MethodAttributes.Public | MethodAttributes.Static, typeof(XmlEntity), new Type[] { typeof(object) });
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0 );
il.Emit(OpCodes.Isinst, typeof(XmlEntity)); il.Emit(OpCodes.Ret); // 返回该值

对应代码:

2、隐式类型转换指令:

1、Box 指令:装箱

示例代码:

MethodBuilder methodBuilder = tb.DefineMethod("ConvertTo", MethodAttributes.Public | MethodAttributes.Static, typeof(object), new Type[] { typeof(int) });
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Box, typeof(int)); il.Emit(OpCodes.Ret); // 返回该值

对应代码:

2、Unbox_Any 指令:拆箱

示例代码:

MethodBuilder methodBuilder = tb.DefineMethod("ConvertTo", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(object) });

ILGenerator il = methodBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Unbox_Any, typeof(int)); il.Emit(OpCodes.Ret); // 返回该值

对应代码:

3、Unbox 指令:拆箱并返回指向值的引用地址

对应代码:

可以看出,返回的是引用,如果需要获取值,需要配置 Ldobj 指令:

来一个示例代码:

var dynamicMethod = new DynamicMethod("ConvertTo", typeof(int), new Type[] { typeof(object) }, typeof(AssMethodIL_Condition));

ILGenerator il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox, typeof(int));
il.Emit(OpCodes.Ldobj, typeof(int)); il.Emit(OpCodes.Ret); // 返回该值 var result = dynamicMethod.Invoke(null, new object[] { 11 });
Console.WriteLine(result);
Console.Read();

运行效果:

可以理解为:

Unbox_Any 指令 = Unbox 指令 + Ldobj 指令。 

3、数值类型转换指令:

在CIL(Common Intermediate Language)中,"conv"(convert)相关指令用于进行类型转换,将一个数据类型转换为另一个数据类型。这些指令通常用于在不同的数据类型之间进行显式转换。

以下是一些常用的"conv"相关指令及其功能:

  1. conv.i1: 将值转换为有符号 8 位整数类型(sbyte)。
  2. conv.i2: 将值转换为有符号 16 位整数类型(short)。
  3. conv.i4: 将值转换为有符号 32 位整数类型(int)。
  4. conv.i8: 将值转换为有符号 64 位整数类型(long)。
  5. conv.u1: 将值转换为无符号 8 位整数类型(byte)。
  6. conv.u2: 将值转换为无符号 16 位整数类型(ushort)。
  7. conv.u4: 将值转换为无符号 32 位整数类型(uint)。
  8. conv.u8: 将值转换为无符号 64 位整数类型(ulong)。
  9. conv.r4: 将值转换为单精度浮点数类型(float)。
  10. conv.r8: 将值转换为双精度浮点数类型(double)。

这些指令在IL代码中用于执行类型转换操作。下面是一个简单的示例,演示如何使用这些指令:

var dynamicMethod = new DynamicMethod("ConvertTo", typeof(float), new Type[] { typeof(int) }, typeof(AssMethodIL_Condition));
ILGenerator il = dynamicMethod.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Conv_R4); il.Emit(OpCodes.Ret); // 返回该值 var result = dynamicMethod.Invoke(null, new object[] { 11 });
Console.WriteLine(result);
Console.Read();

运行结果:

在 Emit 中,类型是需要精确转换的,如果不进行转换,你可能得到类似这样的结果:

总结:

在本教程的第六部分中,我们深入探讨了 ILGenerator 中的类型转换指令。

通过了解这些指令,你可以在动态生成的代码中执行各种类型转换操作,从而更好地控制程序的行为和数据流。

类型转换指令在 .NET 开发中非常有用,特别是在需要进行数据类型转换或操作时。

通过本教程,你应该已经了解了如何使用 ILGenerator 来生成这些转换指令,并且知道它们在 IL 代码中的具体用法和语法。

掌握 ILGenerator 中的类型转换指令将为你的动态代码生成带来更大的灵活性和效率。

继续学习并探索 ILGenerator 中其他功能和指令,以加深对 .NET 平台底层运行机制的理解,并提升自己在 .NET 开发领域的技能水平。

.NET Emit 入门教程:第六部分:IL 指令:8:详解 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. 如何使用疯狂URL获取抖音推流码地址(抖音推流码地址获取教程)

    本节所用到的工具:疯狂URL.OBS推流工具 什么是推流地址? 平时我们如果是下载直播,叫拉流.但如果是你自己要直播,属于上传直播流数据,叫推流,即:把直播流数据推送到视频服务器,然后别人才能看到直播 ...

  2. nvm-windows 安装遇到的问题 node目录卸载后(有残留)记得改名

    需求 网上好多新项目都需要最新版的node,所有需要切换node版本 nvm-windows https://github.com/coreybutler/nvm-windows 安装步骤-问题 删除 ...

  3. C#之winform捕获Console.WriteLine内容到日志文件

    问题描述 之前接手同事的项目,是一个类似于服务端后台的Winform程序,主界面隐藏起来,只再任务栏显示程序图标. 整个项目里面没有日志记录功能,全靠Console.WriteLine打印信息.自己调 ...

  4. 基于DSP的光纤麦克风声音采集系统硬件设计方案总结

    前记  光纤声传感器是一种利用光纤作为传光介质或探测单元的一类声传感器,相比传统电声传感器其具有灵敏度高.频带响应宽.抗电磁干扰等优越特性,可广泛应用于国防安全.工业无损检测.医疗诊断及消费电子等领域 ...

  5. 手动将jar包安装到本地仓库并使用tomcat运行

    参考,欢迎点击原文:https://www.cnblogs.com/panchanggui/p/10696458.html 公司有个老项目是spring的,要我们自己本地安装,我发现我maven一直报 ...

  6. 使用nodejs从控制台读入内容

    在写算法题的时候,基本上都需要输入输出语句,在大多数练题网站上当想用js书写算法题时,发现不知道怎么输入,其实Node是提供了一个readline模块来实现此功能的 tip 笔者用过的练题网站只有le ...

  7. 03.Java数据结构问题

    目录介绍 3.0.0.1 在arrayList中System.arraycopy()和Arrays.copyOf()方法区别联系?System.arraycopy()和Arrays.copyOf()代 ...

  8. 记录--Three.js入门教程——教不会算我输

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 在javascript中使用Three.js设计并且实现3D场景是一个很有意思的事情,因为在浏览器中就能够渲染出3D场景,非常简单和轻便. ...

  9. KingbaseES V8R6数据库运维案例之---用户权限导致的备份恢复故障

    案例说明: 由于限制了用户对数据库的访问,导致在执行'sys_backup.sh init'初始化物理备份时,执行失败. 适用版本: KingbaseES V8R6 一.问题现象 如下所示,执行'sy ...

  10. KingbaseES V8R6 中walminer的使用

    前言 walminer工具可以帮助dba挖掘wal日志中的内容,看到某时间对应数据库中的具体操作.例如挖掘日志后可以看到数据库某时间有哪些dml语句. walminer的限制与约束 WalMiner工 ...