前言:

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

参数加载指令,该加载指令以 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. 视觉slam十四讲CH5 ---相机与图像

    视觉slam十四讲 ---CH5 相机与图像 视觉slam中,作为主要传感器的相机自然起到着重要的作用,而相机拍摄的图像及其处理也是我们要做的工作之一. 1. 相机模型 单目相机的针孔模型 上图中的模 ...

  2. C#实现软件开机自启动(不需要管理员权限)

    目录 原理简介 使用方法 完整代码 原理简介 本文参考C#/WPF/WinForm/程序实现软件开机自动启动的两种常用方法,将里面中的第一种方法做了封装成AutoStart类,使用时直接两三行代码就可 ...

  3. CMake的作用和价值--概念简介

    一 简介: CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程).他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似 ...

  4. 网络io与select

    我们知道网络IO模型一共有5种,这里我们主要讨论同步IO和select多路复用的情况. 我们先从一个简单的TCP服务器的代码出发,来讨论一下这个是怎么实现的. 一个十分简单的TCP服务器 一个简单的T ...

  5. C++多态底层原理:虚函数表

    虚函数表 C++ 对象模型 在有虚函数的情况下,C++对象的模型可以概括为:虚函数表指针+数据struct.在对象所在的内存里:前8个字节(64位系统)是虚函数表所在地址,后边是对象中的member ...

  6. linux使用hostapd+dnsmasq管理多张网卡,搭建dns服务器,并发射wifi热点(支持360wifi等等)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文发布于 2015-03-03 18:37:39 ...

  7. Spring Boot学习日记11

    学习静态资源,和统一打包 WebJars是将web前端资源(js,css等)打成jar包文件然后借助Maven工具,以jar包形式对web前端资源进行统一依赖管理 拿到静态资源 http://loca ...

  8. 基于webpack与TypeScript的SolidJS项目搭建

    本文将讲述如何基于webpack与TypeScript搭建一个基础的支持less模块的solidjs项目.方便后续涉及到solidjs相关分析与讨论都可以基于本文的成果之上进行. 前置 nodejs ...

  9. 记录--使用 JS 实现基本的截图功能

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 思路分析 在开始动手之前,分析一下整个功能的实现过程: 根据图片大小创建 canvas1 画布,并将原图片直接定位在 canvas1 上: ...

  10. [Git]入门及其常用命令

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/17993832 出自[进步*于辰的博客] Git 的难点 ...