.NET Emit 入门教程:第六部分:IL 指令:8:详解 ILGenerator 指令方法:类型转换指令
前言:
经过前面几篇的学习,我们了解到指令的大概分类,如:
参数加载指令,该加载指令以 Ld 开头,将参数加载到栈中,以便于后续执行操作命令。
参数存储指令,其指令以 St 开头,将栈中的数据,存储到指定的变量中,以方便后续使用。
创建实例指令,其指令以 New 开头,用于在运行时动态生成并初始化对象。
方法调用指令,该指令以 Call 开头,用于在运行时调用其它方法。
支条件指令,该指令通常以 Br、或 B、C 开头,用于在运行分支条件时跳转指令。
本篇介绍类型转换指令,该指令通常以 Cast、Conv 开头或box结尾,用于在运行时对类型进行转换。
类型转换指令介绍:
在.NET中,类型转换是一个常见的操作,它允许我们在不同的数据类型之间进行转换。ILGenerator 提供了一系列的指令来执行各种类型转换操作。这些指令可以分为三类:强制类型转换指令、隐式类型转换指令和数值类型转换指令。
强制类型转换指令:这些指令用于执行显式的类型转换操作,如果转换失败则会抛出异常。常见的强制类型转换指令包括
castclass和 isinst 指令。隐式类型转换指令:这些指令用于执行从引用类型到值类型或者从值类型到引用类型的转换,或者在值类型之间执行转换。
unbox和box指令是常见的隐式类型转换指令。数值类型转换指令:这些指令用于执行不同数值类型之间的转换,比如将整数转换为浮点数,或者将浮点数转换为整数。
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"相关指令及其功能:
conv.i1: 将值转换为有符号 8 位整数类型(sbyte)。conv.i2: 将值转换为有符号 16 位整数类型(short)。conv.i4: 将值转换为有符号 32 位整数类型(int)。conv.i8: 将值转换为有符号 64 位整数类型(long)。conv.u1: 将值转换为无符号 8 位整数类型(byte)。conv.u2: 将值转换为无符号 16 位整数类型(ushort)。conv.u4: 将值转换为无符号 32 位整数类型(uint)。conv.u8: 将值转换为无符号 64 位整数类型(ulong)。conv.r4: 将值转换为单精度浮点数类型(float)。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 指令方法:类型转换指令的更多相关文章
- Golang入门教程(十三)延迟函数defer详解
前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...
- Docker入门教程(六)另外的15个Docker命令
Docker入门教程(六)另外的15个Docker命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第六篇,继续介绍Docker命令.之前的第二篇文章 ...
- 无废话ExtJs 入门教程十六[页面布局:Layout]
无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...
- Photoshop入门教程(六):通道
学习心得:当大部分人听到通道.心里可能会有一种很害怕的感觉,因为“通道”并不像“图层”这样易于理解,望而生畏.”通道“的本质其实是存储图片的信息,把一张图片比作一个为网站,那么通道就是网站的后台,存储 ...
- RabbitMQ入门教程(十六):RabbitMQ与Spring集成
原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...
- ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解
原文 ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 ...
- SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解
SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解 博客分类: 跟开涛学SpringMVC 6.6.2.@RequestParam绑定单个请求参数值 @RequestParam用于 ...
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- SaltStack 入门到精通第二篇:Salt-master配置文件详解
SaltStack 入门到精通第二篇:Salt-master配置文件详解 转自(coocla):http://blog.coocla.org/301.html 原本想要重新翻译salt-mas ...
- 【入门】广电行业DNS、DHCP解决方案详解(三)——DNS部署架构及案
[入门]广电行业DNS.DHCP解决方案详解(三)——DNS部署架构及案 DNS系统部署架构 宽带业务DNS架构 互动业务DNS架构 案例介绍 案例一 案例二 本篇我们将先介绍DNS系统部署架构体系, ...
随机推荐
- 机器学习策略篇:详解训练/开发/测试集划分(Train/dev/test distributions)
训练/开发/测试集划分 设立训练集,开发集和测试集的方式大大影响了或者团队在建立机器学习应用方面取得进展的速度.同样的团队,即使是大公司里的团队,在设立这些数据集的方式,真的会让团队的进展变慢而不是加 ...
- kafka 工作流程及文件存储机制
1.kafka的数据存储 文件存储格式: .log 和 .index Kafka 中消息是以 topic 进行分类的, 生产者生产消息,消费者消费消息,都是面向 topic的. topic ...
- Redis单线程为什么如此之快
一.概述 Redis的高并发和快简单可以归结为一下几点: 1.Redis是基于内存的: 2.Redis是单线程的: 3.Redis使用多路复用技术. 4.高效的数据结构 但具体怎么做的呢,下面来详细看 ...
- Spring事务(一)-事务配置
事务是数据库操作最基本的单元,是逻辑上的一组操作,这一组操作在同一个会话中要么都执行成功,要么都失败,这也是事务的最基本特性--原子性.事务的作用是为了保证系统数据的正确性,因此,数据库应用程序中是会 ...
- vscode 当做记事本,用任务 tasks 自动提交git - ctrl shift B
vscode 当做记事本,用任务 tasks 自动提交git - ctrl shift B 起因 开始用的joplin 本地记事本挺好,唯一缺点不能同步. 用了一下,发现markdown是两栏的,变成 ...
- 新版idea配置maven注意点!!
1. maven配置 首先是按要求配置了maven,关闭所有项目->自定义->所有设置 配置完成之后发现新建项目下方还是显示从官方源下载maven包装器,而且在项目中出现这个配置文件 可以 ...
- 干货分享 | 3个Zbrush实用减面工具分享
一.使用Sculptris Pro Sculptris Pro是zbrush中的一个功能按钮,点击此工具按钮,同时将笔刷转换至standard笔刷,即可减去需要平滑的面. 点击开启Sculptris ...
- iOS Modern Collection View
TL;DR 使用的技术: Compositional layout + Diffable data source.iOS 14+. 创建 layout 以描述布局: 创建 dataSource 以提供 ...
- docker-compose安装mysql8+踩坑版
一.拉取MySQL镜像 我这里使用的是MySQL8.0.18,可以自行选择需要的版本. docker pull mysql:8.0.18 二.创建挂载目录 mkdir -p /home/docker/ ...
- KingbaseESV8R6全局临时表不能进行reindex操作
背景 我们经常遇到两种情况下会重建索引,reindex 1.索引崩溃,由于软件或硬件问题导致索引内数据失效而不可用. 2.索引膨胀,当索引膨胀会占用过多磁盘空间,reindex可以解决此问题. 对于临 ...