如何用IL Emit为非标准类型(如Type)的局部变量赋值?
问题解决:IL Emit为Type类型局部变量赋值
原代码错误原因
你当前的IL代码核心错误在于:OpCodes.Ldloc是用来加载当前方法内的局部变量,但你传入的是C#层面的types变量(外部变量),IL运行时根本无法识别这个对象,直接导致程序无效。
解决方案:通过编译+反编译参考正确IL逻辑
步骤1:编写等效逻辑的普通C#方法
先写一个和目标逻辑完全一致的静态方法,让编译器帮我们生成正确的IL:
using System.Text; public static void TestTypeAssignment() { Type t = typeof(StringBuilder); Console.WriteLine(t); }
步骤2:反编译查看IL代码
用ILSpy、dotnet ildasm等工具反编译该方法,得到正确的IL指令:
.method public hidebysig static void TestTypeAssignment() cil managed { .maxstack 1 .locals init ([0] class [System.Runtime]System.Type t) IL_0000: ldtoken [System.Text]System.Text.StringBuilder IL_0005: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) IL_000a: stloc.0 IL_000b: ldloc.0 IL_000c: call void [System.Console]System.Console::WriteLine(object) IL_0011: ret }
步骤3:对照IL编写正确的Emit代码
根据反编译得到的IL,修正你的DynamicMethod代码:
using System.Reflection; using System.Reflection.Emit; using System.Text; DynamicMethod dynamicMethod = new DynamicMethod("test", null, null); var il = dynamicMethod.GetILGenerator(); LocalBuilder ilType = il.DeclareLocal(typeof(Type)); // 1. 加载StringBuilder的元数据令牌,调用GetTypeFromHandle获取Type实例 il.Emit(OpCodes.Ldtoken, typeof(StringBuilder)); il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) })!); // 2. 将Type实例存入局部变量 il.Emit(OpCodes.Stloc, ilType); // 3. 加载局部变量并输出 il.Emit(OpCodes.Ldloc, ilType); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) })!); // 4. 返回 il.Emit(OpCodes.Ret); dynamicMethod.CreateDelegate(typeof(Action)).DynamicInvoke();
关键逻辑说明
- 要在IL中获取
Type实例,不能直接引用外部C#变量,必须通过Ldtoken指令加载目标类型的元数据令牌,再调用Type.GetTypeFromHandle方法生成Type对象。 - 局部变量的操作必须严格遵循栈逻辑:先把值推入栈,再用
Stloc存入局部变量;读取时用Ldloc把局部变量的值推入栈。
内容的提问来源于stack exchange,提问作者DamXosp4j
相关产品推荐
相关产品推荐

