这一篇讲解方法内的局部变量是怎么声明、怎样保存、怎样加载的。

声明局部变量
声明用ILGenerator的DeclareLocal方法,参数是局部变量的数据类型,得到一个局部变量对应的创建类LocalBuilder。
使用格式是
LocalBuilder localBuilderx = ilGenerator.DeclareLocal(typeof(<数据类型>));
实际例子

LocalBuilder localBuilderv1 = ilGenerator.DeclareLocal(typeof(string));//声明一个string类型局部变量
LocalBuilder localBuilderv2 = ilGenerator.DeclareLocal(typeof(int));//声明一个int类型局部变量

LocalBuilder对象有两个重要的属性LocalType和LocalIndex。
属性LocalType的数据类型是System.Type,它表示的是这个局部变量的数据类型。
属性LocalIndex是int类型,它表示的是这个局部变量在这个方法体内的局部变量索引,并且是从0 开始的;假如这个局
部变量所在方法体的ilGenerator第n次调用DeclareLocal方法,那么它的LocalIndex就是(n-1)。

保存局部变量
保存局部变量的指令是Stloc、Stloc_S、Stloc_0、Stloc_1、Stloc_2、Stloc_3。
Stloc是通用指令;
当LocalBuilder的LocalIndex在0到255之间时,推荐用Stloc_S;
当LocalBuilder的LocalIndex为0时,推荐用Stloc_0;
当LocalBuilder的LocalIndex为1时,推荐用Stloc_1;
当LocalBuilder的LocalIndex为2时,推荐用Stloc_2;
当LocalBuilder的LocalIndex为3时,推荐用Stloc_3。
可以把这些指令用一个方法进行包装,源码如下

public static void StormLocal(ILGenerator ilGenerator, LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Stloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_3);
return;
}
if (localIndex > && localIndex <= )
{
ilGenerator.Emit(OpCodes.Stloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Stloc, localIndex);
return;
}
}

加载局部变量
把局部变量加载到运算栈上的指令是Ldloc、Ldloc_S、Ldloc_0、Ldloc_1、Ldloc_2、Ldloc_3。
Ldloc是通用指令;
当LocalBuilder的LocalIndex在0到255之间时,推荐用Ldloc_S;
当LocalBuilder的LocalIndex为0时,推荐用Ldloc_0;
当LocalBuilder的LocalIndex为1时,推荐用Ldloc_1;
当LocalBuilder的LocalIndex为2时,推荐用Ldloc_2;
当LocalBuilder的LocalIndex为3时,推荐用Ldloc_3。
可以把这些指令用一个方法进行包装,源码如下

        public static void LoadLocal(ILGenerator ilGenerator,LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Ldloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_3);
return;
}
if(localIndex> && localIndex<=)
{
ilGenerator.Emit(OpCodes.Ldloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Ldloc, localIndex);
return;
}
}

完整的程序如下

using System;
using System.Reflection;
using System.Reflection.Emit; namespace LX1_ILDemo
{
class Demo04_Local
{
static string binaryName = "Demo04_Local.exe";
static string namespaceName = "LX1_ILDemo";
static string typeName = "EmitLocal"; static AssemblyBuilder assemblyBuilder;
static ModuleBuilder moduleBuilder;
static TypeBuilder typeBuilder;
static MethodBuilder mainMethod;
static ILGenerator ilGenerator; static void Emit_ILCode()
{
MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) });
MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); /* string v1; */
LocalBuilder localBuilderv1 = ilGenerator.DeclareLocal(typeof(string));//声明一个string类型局部变量,第一次声明一个变量,所以它的LocalIndex是0 /* v1="hello"; */
ilGenerator.Emit(OpCodes.Ldstr,"hello");
ilGenerator.Emit(OpCodes. Stloc_0 );
/* Console.WriteLine(v1); */
ilGenerator.Emit(OpCodes.Ldloc_0);
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod); /* v1="hello"; */
ilGenerator.Emit(OpCodes.Ldstr, "world");
StormLocal(ilGenerator, localBuilderv1);
/* Console.WriteLine(v1); */
LoadLocal(ilGenerator, localBuilderv1);
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod); /* int v2; */
LocalBuilder localBuilderv2 = ilGenerator.DeclareLocal(typeof(int));//声明一个int类型局部变量,第二次声明一个变量,所以它的LocalIndex是1 /* v2=int.MaxValue; */
ilGenerator.Emit(OpCodes.Ldc_I4,int.MaxValue);
ilGenerator.Emit(OpCodes.Stloc_1);
/* Console.WriteLine(v2); */
ilGenerator.Emit(OpCodes.Ldloc_1);
ilGenerator.Emit(OpCodes.Call, writeIntLineMethod); /* v1=int.MinValue; */
ilGenerator.Emit(OpCodes.Ldc_I4, int.MinValue);
StormLocal(ilGenerator, localBuilderv2);
/* Console.WriteLine(v2); */
LoadLocal(ilGenerator, localBuilderv2);
ilGenerator.Emit(OpCodes.Call, writeIntLineMethod); } public static void LoadLocal(ILGenerator ilGenerator,LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Ldloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_3);
return;
}
if(localIndex> && localIndex<=)
{
ilGenerator.Emit(OpCodes.Ldloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Ldloc, localIndex);
return;
}
} public static void StormLocal(ILGenerator ilGenerator, LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Stloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_3);
return;
}
if (localIndex > && localIndex <= )
{
ilGenerator.Emit(OpCodes.Stloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Stloc, localIndex);
return;
}
} public static void Generate()
{
InitAssembly(); /* 生成 public class LoadLFDSN */
typeBuilder = moduleBuilder.DefineType(namespaceName + "." + typeName, TypeAttributes.Public); /* 生成 public static void Main() */
GenerateMain(); Emit_ILCode(); EmitReadKey();
ilGenerator.Emit(OpCodes.Ret); /* 设置assembly入口方法 */
assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication); SaveAssembly();
Console.WriteLine("生成成功");
} static void EmitReadKey()
{
/* 生成 Console.ReadKey(); */
MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { });
ilGenerator.Emit(OpCodes.Call, readKeyMethod);
ilGenerator.Emit(OpCodes.Pop);
} static void GenerateMain()
{
mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public
| MethodAttributes.Static, typeof(void), new Type[] { });
ilGenerator = mainMethod.GetILGenerator();
} 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实用指南-生成索引器

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

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

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

  3. TensorFlow模型保存和加载方法

    TensorFlow模型保存和加载方法 模型保存 import tensorflow as tf w1 = tf.Variable(tf.constant(2.0, shape=[1]), name= ...

  4. 背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别

    [源码下载] 背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别 作者:webabcd 介绍背水一战 Windows 10 之 控件(媒体类) ...

  5. keras中的模型保存和加载

    tensorflow中的模型常常是protobuf格式,这种格式既可以是二进制也可以是文本.keras模型保存和加载与tensorflow不同,keras中的模型保存和加载往往是保存成hdf5格式. ...

  6. 完美实现保存和加载easyui datagrid自定义调整列宽位置隐藏属性功能

    需求&场景 例表查询是业务系统中使用最多也是最基础功能,但也是调整最平凡,不同的用户对数据的要求也不一样,所以在系统正式使用后,做为开发恨不得坐在业务边上,根据他们的要求进行调整,需要调整最多 ...

  7. 从头学pytorch(十二):模型保存和加载

    模型读取和存储 总结下来,就是几个函数 torch.load()/torch.save() 通过python的pickle完成序列化与反序列化.完成内存<-->磁盘转换. Module.s ...

  8. 使用Pytorch在多GPU下保存和加载训练模型参数遇到的问题

    最近使用Pytorch在学习一个深度学习项目,在模型保存和加载过程中遇到了问题,最终通过在网卡查找资料得已解决,故以此记之,以备忘却. 首先,是在使用多GPU进行模型训练的过程中,在保存模型参数时,应 ...

  9. MSIL实用指南-加载bool、sbyte、byte、char、short等值

    这一篇讲解怎么加载bool值.sbyte值.byte值.char值.short值. 加载bool值在.NET程序实际运行中,是没有true和false值的,实际上是以1和0表示它们,加载它们的指令是L ...

随机推荐

  1. Yaf框架的配置

    http://www.laruence.com/manual/yaf.ini.html //先看一下惠新宸鸟哥yaf官网的配置说明 我们可以在php.ini中定义开发环节配置项,把本地开发设置成dev ...

  2. Redis的两种持久化方式-快照持久化和AOF持久化

    Redis为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边,数据保存到硬盘的过程就称为"持久化"效 ...

  3. length()方法,length属性和size()的方法的区别

    length()方法,length属性和size()的方法的区别: length()方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法: length属性是针对Java中的数 ...

  4. java网络编程(4)——udp实现聊天

    UDP可以实现在线聊天功能,我这里就是简单模拟一下: 发送端: package com.seven.udp; import java.io.BufferedReader; import java.io ...

  5. 通讯服务类API调用的代码示例合集:短信服务、手机号归属地查询、电信基站查询等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 短信服务:通知类和验证码短信,全国三网合一通道,5秒内到达,费用低 ...

  6. git 命令和使用场景总结

    资料地址:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000    http://w ...

  7. php-fpm问题

    这个问题怎么说呢?之前遇到这个问题内心是奔溃的.因为我压根不知道是哪里出问题啦.不过,在我努力探索下,最终还是解决了问题. so请记住,坚持不一定成功,但放弃一定失败. 简单描述一下问题: 1.本地的 ...

  8. MS SQL xp_instance_regwrite设置注册表疑惑

      以前写过一篇博文"MS SQL 日志记录管理",里面介绍了如何设置SQL Server的错误日志的最大归档数量,如果在SSMS的UI界面设置,可以从"Manageme ...

  9. java代码中init method和destroy method的三种使用方式

    在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...

  10. jvm类加载器和双亲委派模型

    类加载器按照层次,从顶层到底层,分为以下三种:  (1)启动类加载器(Bootstrap ClassLoader)   这个类加载器负责将存放在JAVA_HOME/lib下的,或者被-Xbootcla ...