MSIL实用指南-加载和保存参数
本篇讲解怎么加载和保存参数,以及参数起始序号的确定。
参数的加载
加载参数的指令是Ldarg、Ldarg_S、Ldarg_0、Ldarg_1、Ldarg_2、Ldarg_3。
Ldarg_0是加载第0个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_0);
Ldarg_1是加载第1个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_1);
Ldarg_2是加载第2个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_2);
Ldarg_3是加载第3个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_3);
Ldarg_S是加载次序为0到255的参数,例子 ilGenerator.Emit(OpCodes.Ldarg_S,5);
Ldarg加载任意次序的参数,例子 ilGenerator.Emit(OpCodes.Ldarg,6)。
我们可以根据指令的说明实现一个方便调用的方法,源码如下
public static void LoadArg(ILGenerator ilGenerator, int argIndex) { switch (argIndex) { case 0: ilGenerator.Emit(OpCodes.Ldarg_0); return; case 1: ilGenerator.Emit(OpCodes.Ldarg_1); return; case 2: ilGenerator.Emit(OpCodes.Ldarg_2); return; case 3: ilGenerator.Emit(OpCodes.Ldarg_3); return; } if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Ldarg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Ldarg, argIndex); return; } }
参数的保存
保存参数的指令是Starg、Starg_S
Ldarg_S是保存次序为0到255的参数,例子 ilGenerator.Emit(OpCodes.Starg_S,1);
Starg加载任意次序的参数,例子 ilGenerator.Emit(OpCodes.Starg,6)。
我们可以根据指令的说明实现一个方便调用的方法,源码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static void StormArg(ILGenerator ilGenerator, int argIndex) { if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Starg_S, argIndex); return ; } else { ilGenerator.Emit(OpCodes.Starg, argIndex); return ; } } |
参数起始序号的确定
参数的起始序号不一定从0开始,也可能从1开始,这是由方法是否是static决定的。
如果参数所在的方法是static修饰的,序号从0开始;
如果不是static修饰,则从0开始。
完整的一个例子如下

using System; using System.Reflection; using System.Reflection.Emit; namespace LX1_ILDemo { class Demo08_Arg { static string binaryName = "Demo08_Arg.exe"; static string namespaceName = "LX1_ILDemo"; static string typeName = "ArgTest"; static AssemblyBuilder assemblyBuilder; static ModuleBuilder moduleBuilder; static TypeBuilder typeBuilder; static MethodBuilder mainMethod; static MethodBuilder printStaticMethod; static MethodBuilder printInstaceMethod; static ConstructorBuilder constructorBuilder; static void Emit_PrintInstace() { printInstaceMethod = typeBuilder.DefineMethod("PrintInstanceArg", MethodAttributes.Public, typeof(void), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(string) }); ILGenerator printILInstaceGenerator = printInstaceMethod.GetILGenerator(); ParameterBuilder ab1 = printStaticMethod.DefineParameter(1, ParameterAttributes.None, "i1"); ParameterBuilder ab2 = printStaticMethod.DefineParameter(2, ParameterAttributes.None, "i2"); ParameterBuilder ab3 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i3"); ParameterBuilder ab4 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i4"); ParameterBuilder ab5 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "s5"); MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }); MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); LoadArg(printILInstaceGenerator,1); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 2); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 3); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 4); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 5); printILInstaceGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILInstaceGenerator.Emit(OpCodes.Ldstr, "world"); StormArg(printILInstaceGenerator, 5); LoadArg(printILInstaceGenerator, 5); printILInstaceGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILInstaceGenerator.Emit(OpCodes.Ret); } public static void LoadArg(ILGenerator ilGenerator, int argIndex) { switch (argIndex) { case 0: ilGenerator.Emit(OpCodes.Ldarg_0); return; case 1: ilGenerator.Emit(OpCodes.Ldarg_1); return; case 2: ilGenerator.Emit(OpCodes.Ldarg_2); return; case 3: ilGenerator.Emit(OpCodes.Ldarg_3); return; } if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Ldarg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Ldarg, argIndex); return; } } public static void StormArg(ILGenerator ilGenerator, int argIndex) { if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Starg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Starg, argIndex); return; } } static void Emit_PrintStatic() { printStaticMethod = typeBuilder.DefineMethod("PrintStaticArg", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(string) }); ILGenerator printILGenerator = printStaticMethod.GetILGenerator(); ParameterBuilder ab1 = printStaticMethod.DefineParameter(1, ParameterAttributes.None, "i1"); ParameterBuilder ab2 = printStaticMethod.DefineParameter(2, ParameterAttributes.None, "i2"); ParameterBuilder ab3 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i3"); ParameterBuilder ab4 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i4"); ParameterBuilder ab5 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "s5"); MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }); MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); printILGenerator.Emit(OpCodes.Ldarg_0); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_1); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_2); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_3); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_S,4); printILGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILGenerator.Emit(OpCodes.Ldstr, "world"); printILGenerator.Emit(OpCodes.Starg_S, 4); printILGenerator.Emit(OpCodes.Ldarg_S, 4); printILGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILGenerator.Emit(OpCodes.Ret); } public static void Generate() { InitAssembly(); typeBuilder = moduleBuilder.DefineType( namespaceName+"."+ typeName, TypeAttributes.Public); constructorBuilder = typeBuilder.DefineDefaultConstructor( MethodAttributes.Public); Emit_PrintStatic(); Emit_PrintInstace(); EmitMain(); /* 设置assembly入口方法 */ assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication); SaveAssembly(); Console.WriteLine("生成成功"); } static void EmitMain() { mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { }); ILGenerator mainILGenerator = mainMethod.GetILGenerator(); mainILGenerator.Emit(OpCodes.Ldc_I4,(int)200); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)300); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)400); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)500); mainILGenerator.Emit(OpCodes.Ldstr,"hello static"); mainILGenerator.Emit(OpCodes.Call, printStaticMethod); LocalBuilder localBuilder = mainILGenerator.DeclareLocal(typeof(string)); mainILGenerator.Emit(OpCodes.Newobj, constructorBuilder); mainILGenerator.Emit(OpCodes.Stloc_0); mainILGenerator.Emit(OpCodes.Ldloc_0); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)200); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)300); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)400); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)500); mainILGenerator.Emit(OpCodes.Ldstr, "hello instance"); mainILGenerator.Emit(OpCodes.Call, printInstaceMethod); MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { }); mainILGenerator.Emit(OpCodes.Call, readKeyMethod); mainILGenerator.Emit(OpCodes.Pop); mainILGenerator.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); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?