数值的比较就是大于、小于、等于、大于等于、小于等于、不等于,它们的运算结果都是布尔值。
大于、小于、等于有直接对应的指令,分别是Cgt、Clt、Ceq。
大于等于、小于等于、不等于没有直接对应的指令,它的运算实现一般是取反。

大于、小于、等于需要两个参数,它们的通用步骤
1.生成加载左边变量
2.生成加载右边变量
3.生成比较运算指令

生成等于比较的代码实例:

ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ceq);

下面以生成大于等于为例子,讲解一下怎么生成相应运算指令。
前两个步骤还是生成加载左右参数。
“生成等于”其实就是“不大于”,按顺序就是先比较是否是小于,然后把这个结果和false比较。
IL指令中0代表false。
即生成

ilGenerator.Emit(OpCodes.Clt);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);

小于等于则是进行大于比较,然后再和0比较

ilGenerator.Emit(OpCodes.Cgt);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);

不等于是先进行等于比较,然后看这个结果是否是false

ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);

上面可以看出,最后两条指令是固定的,都是和false比较,获得最终结果。

完整的程序如下

using System;
using System.Reflection;
using System.Reflection.Emit; namespace LX1_ILDemo
{
class Demo19_CompareOP
{
static string binaryName = "Demo19_CompareOP.exe";
static string namespaceName = "LX1_ILDemo";
static string typeName = "CompareOPDemo"; static AssemblyBuilder assemblyBuilder;
static ModuleBuilder moduleBuilder;
static TypeBuilder typeBuilder;
static MethodBuilder mainMethod;
static MethodBuilder testMethod; static void Emit_Test()
{
testMethod = typeBuilder.DefineMethod("TestCompare", MethodAttributes.Public
| MethodAttributes.Static, typeof(void), new Type[] { typeof(int), typeof(int) });
var println = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) });
var ilGenerator = testMethod.GetILGenerator();
// >
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Cgt);
ilGenerator.Emit(OpCodes.Call, println); // <
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Clt);
ilGenerator.Emit(OpCodes.Call, println); // ==
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Call, println); //>=
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Clt);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Call, println); // <=
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Cgt);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Call, println); //!=
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Call, println); ilGenerator.Emit(OpCodes.Ret);
} public static void Generate()
{
InitAssembly();
typeBuilder = moduleBuilder.DefineType(namespaceName + "." + typeName, TypeAttributes.Public);
Emit_Test();
GenerateMain();
assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication);
SaveAssembly();
Console.WriteLine("生成成功");
} static void GenerateMain()
{
mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public
| MethodAttributes.Static, typeof(void), new Type[] { });
var ilGenerator = mainMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldc_I4_1);
ilGenerator.Emit(OpCodes.Ldc_I4_7);
ilGenerator.Emit(OpCodes.Call, testMethod); ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadKey", new Type[] { }));
ilGenerator.Emit(OpCodes.Pop);
ilGenerator.Emit(OpCodes.Ret);
} static void InitAssembly()
{
AssemblyName assemblyName = new AssemblyName(namespaceName);
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, binaryName);
} static void SaveAssembly()
{
Type t = typeBuilder.CreateType(); //完成Type,这是必须的
assemblyBuilder.Save(binaryName);
}
}
}

MSIL实用指南-比较运算的更多相关文章

  1. MSIL实用指南-位运算

    C#支持的位运算是与.或.异或.取反.左移.右移,它们对应的指令是And.Or.Xor.Not.Shl.Shr. 取反运算只需要一个操作数,生成步骤是1.生成加载变量2.生成取反指令实例代码: ilG ...

  2. MSIL实用指南-数学运算

    C#支持的数学运算是加.减.乘.除.取模,它们对应的指令是Add.Sub.Mul.Div.Rem. 这五个运算都需要两个参数,它们的通用步骤1.生成加载左边变量2.生成加载右边变量3.生成运算指令 实 ...

  3. MSIL实用指南-生成索引器

    MSIL实用指南-生成索引器 索引器是一种特殊的属性,它有参数的,也有get和set方法,属性名称一般是"Item",并且方法名称一般名称是"get_Item" ...

  4. MSIL实用指南-Action的生成和调用

    MSIL实用指南-Action的生成和调用 System.Action用于封装一个没有参数没有返回值的方法.这里生成需要Ldftn指令. 下面讲解怎生成如下的程序. class ActionTest ...

  5. MSIL实用指南-局部变量的声明、保存和加载

    这一篇讲解方法内的局部变量是怎么声明.怎样保存.怎样加载的. 声明局部变量声明用ILGenerator的DeclareLocal方法,参数是局部变量的数据类型,得到一个局部变量对应的创建类LocalB ...

  6. MSIL实用指南-逻辑运算

    逻辑运算有三种:与.或.非.实现它们可以用位运算指令And.Or.Not等三个指令.它们的使用方法和位运算一致. 完整的程序如下: using System; using System.Reflect ...

  7. MSIL实用指南-加载int值

    这一篇讲的是怎样加载整数值到运算栈上.这一类的指令都是以Ldc_I4开头. Ldc_I4类OpCodes的Ldc_I4字段的功能是把一个int值压入运算栈上.它的使用方法是ilGenerator.Em ...

  8. MSIL实用指南-IL版hello world

    我们学习编程开始时,一般用输出"hello world"的一段程序. C#版的"hello world"是 using System; namespace L0 ...

  9. MSIL实用指南-加载null、string、long、float、double等值

    本篇讲述怎么加载null.string值.long值.float值.double值. 加载null不需要参数值,只要 Emit ldnull 其它几个命令要 Emit <指令> <值 ...

随机推荐

  1. CentOS 下编译安装MySQL

    CnetOS 下编译安装 MySql 查看是否存在旧版本: rpm -qa | grep mysql 卸载旧版本: rpm -e mysql   #普通删除模式 rpm -e --nodeps mys ...

  2. mysql协议分析1---报文的格式和基本类型

    navicat 和 mysql 是一对好基友,每天都有非常频繁的交流,主人在navicat上写下每条sql语句,轻轻的点了下执行按钮,navicat就飞快的把主人的指令传送到mysql那里,mysql ...

  3. 牛客第十场Rikka with Prefix Sum

    由于其中的2操作非常多,我们就需要将其快速的更改,就会用到组合数的东西 其实自己手写一下就可以发现对于一个点增加的值在经过不断地前缀和累加过程中对于一点的贡献满足杨辉三角 所以我们就需要记录一下其中的 ...

  4. @ConfigurationProperties 注解使用姿势,这一篇就够了

    在编写项目代码时,我们要求更灵活的配置,更好的模块化整合.在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或 applicat ...

  5. Java 内存模型详解

    概述 Java的内存模型(Java Memory Model )简称JMM.首先应该明白,Java内存模型是一个规范,主要规定了以下两点: 规定了一个线程如何以及何时可以看到其他线程修改过后的共享变量 ...

  6. 2019最新idea注册码

    2019最新注册码到2020年1月7号 N757JE0KCT-eyJsaWNlbnNlSWQiOiJONzU3SkUwS0NUIiwibGljZW5zZWVOYW1lIjoid3UgYW5qdW4iL ...

  7. 读写properties文件

    1. 读properties文件 Properties props = new Properties(); try { InputStream in = new FileInputStream(&qu ...

  8. Jenkins 配置 SpringBoot 自动构建部署

    服务器版本 Linux version 3.10.0-957.12.1.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8 ...

  9. 使用Yapi展示你的api接口

    今天研究了下一款非常好用的api集中展示工具---Yapi,具体网址 https://hellosean1025.github.io/yapi/documents/index.html 如图,看下基本 ...

  10. 使用Jasypt对SpringBoot配置文件加密

    # **前言** 在日前安全形势越来越严重的情况下,让我意识到在项目中存在一个我们经常忽略的漏洞,那就是我们的项目的配置文件中配置信息的安全,尤其是数据库连接的用户名和密码的安全.所以这里我们就需要对 ...