Излучать IL как метод C # IL, но получить System.InvalidProgramException: во время выполнения Common Language обнаружил недопустимую программу - PullRequest
1 голос
/ 27 сентября 2019

Излучать IL как метод C # IL, но получить System.InvalidProgramException: Common Language Runtime обнаружил недопустимую программу.

Пример:

    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, а не метод демо-метода eqauls 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);
    }
}


1 Ответ

3 голосов
/ 27 сентября 2019

Поскольку вы сохраняете значение в локальной переменной с помощью stloc.0, вам необходимо объявить его:

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

В вашей второй версии нет локальных переменных, поэтому у нее нет этой проблемы.

Первая версия - это то, что компилятор выдает в режиме отладки, но в режиме выпуска это больше похоже на ваш второй пример (за исключением nop, который не нужен).

...