像 C# 方法 IL 一样发出 IL 但获取 System.InvalidProgramException:公共语言运行时检测到无效程序

Emit IL Like C# Method IL But Get System.InvalidProgramException : Common Language Runtime detected an invalid program

像 C# 方法 IL 一样发出 IL 但获取 System.InvalidProgramException:公共语言运行时检测到无效程序。

示例:

    public static int BoolToInt(this bool input)
    {
        return input ? 1 : 0;
    }

IL 代码是:

ExtensionDataGetter.BoolToInt:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  brtrue.s    IL_0007
IL_0004:  ldc.i4.0    
IL_0005:  br.s        IL_0008
IL_0007:  ldc.i4.1    
IL_0008:  stloc.0     
IL_0009:  br.s        IL_000B
IL_000B:  ldloc.0     
IL_000C:  ret         

我尝试使用 Emit IL 创建此方法:

class Program
{
    static void Main(string[] args)
    {
        var result = CreateFunc()(true);
        Console.WriteLine(result);
    }

    static Func<bool, int> CreateFunc()
    {
        var dm = new DynamicMethod("Test" + Guid.NewGuid().ToString(), typeof(int), new[] { typeof(bool) });
        var il = dm.GetILGenerator();

        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Ldarg_0);

        var labelTrue = il.DefineLabel();
        var labelStloc = il.DefineLabel();
        var labelReturn = il.DefineLabel();

        il.Emit(OpCodes.Brtrue_S, labelTrue); 
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Br_S, labelStloc);
        il.MarkLabel(labelTrue);
        il.Emit(OpCodes.Ldc_I4_1);
        il.MarkLabel(labelStloc);
        il.Emit(OpCodes.Stloc_0);

        il.Emit(OpCodes.Br_S, labelReturn); 
        il.MarkLabel(labelReturn);
        il.Emit(OpCodes.Ldloc_0); 
        il.Emit(OpCodes.Ret);

        var funcType = System.Linq.Expressions.Expression.GetFuncType(typeof(bool), typeof(int));
        return (Func<bool, int>)dm.CreateDelegate(funcType);
    }
}

但是低于错误

System.InvalidProgramException
  HResult=0x8013153A
  Message=Common Language Runtime detected an invalid program.
  Source=<Cannot evaluate the exception source>
  StackTrace:
<Cannot evaluate the exception stack trace>

我试着按照我的逻辑写一个新版本,它成功了。
但它是 IL 不等于演示方法的 IL

using System;
using System.Reflection;
using System.Reflection.Emit;


class Program
{
    static void Main(string[] args)
    {
        var func = CreateFunc();
        Console.WriteLine(func(true));
        Console.WriteLine(func(false));
    }

    static Func<bool, int> CreateFunc()
    {
        var dm = new DynamicMethod("Test" + Guid.NewGuid().ToString(), typeof(int), new[] { typeof(bool) });

        var il = dm.GetILGenerator();
        var labelTrue = il.DefineLabel();

        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Brtrue_S, labelTrue); 
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Ret);
        il.MarkLabel(labelTrue);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Ret);

        var funcType = System.Linq.Expressions.Expression.GetFuncType(typeof(bool), typeof(int));
        return (Func<bool, int>)dm.CreateDelegate(funcType);
    }
}


由于您使用 stloc.0 将值存储在局部变量中,因此需要声明它:

var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int));

你的第二个版本没有使用本地化所以没有这个问题。

第一个版本是编译器在调试模式下发出的,但在发布模式下它更像您的第二个示例(除了不需要的 nop)。