MSIL实用指南-局部变量的声明、保存和加载
这一篇讲解方法内的局部变量是怎么声明、怎样保存、怎样加载的。
声明局部变量
声明用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 0: ilGenerator.Emit(OpCodes.Stloc_0); return; case 1: ilGenerator.Emit(OpCodes.Stloc_1); return; case 2: ilGenerator.Emit(OpCodes.Stloc_2); return; case 3: ilGenerator.Emit(OpCodes.Stloc_3); return; } if (localIndex > 0 && localIndex <= 255) { 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 0: ilGenerator.Emit(OpCodes.Ldloc_0); return; case 1: ilGenerator.Emit(OpCodes.Ldloc_1); return; case 2: ilGenerator.Emit(OpCodes.Ldloc_2); return; case 3: ilGenerator.Emit(OpCodes.Ldloc_3); return; } if(localIndex>0 && localIndex<=255) { 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 0: ilGenerator.Emit(OpCodes.Ldloc_0); return; case 1: ilGenerator.Emit(OpCodes.Ldloc_1); return; case 2: ilGenerator.Emit(OpCodes.Ldloc_2); return; case 3: ilGenerator.Emit(OpCodes.Ldloc_3); return; } if(localIndex>0 && localIndex<=255) { 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 0: ilGenerator.Emit(OpCodes.Stloc_0); return; case 1: ilGenerator.Emit(OpCodes.Stloc_1); return; case 2: ilGenerator.Emit(OpCodes.Stloc_2); return; case 3: ilGenerator.Emit(OpCodes.Stloc_3); return; } if (localIndex > 0 && localIndex <= 255) { 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); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?