Ошибка JIT-компилятора - недопустимое исключение программы при использовании Reflection.Emit - PullRequest
0 голосов
/ 07 апреля 2010

Может кто-нибудь объяснить мне, почему следующее работает для первого теста, но выдает InvalidProgramException для второго теста? Я в тупике.

using System;
using System.Reflection;
using System.Reflection.Emit;</p>

<p>namespace DMTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Test.NewResultWithParam();
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
            Test.NewResult();
            Console.WriteLine("Press any key to exit");
            Console.ReadLine();
        }
    }</p>

public static class Test
{
    public static void NewResult()
    {
        var f = typeof(Result).New<Result>();
        var result = f.Invoke();
    }

    public static void NewResultWithParam()
    {
        var f = typeof(Result).New<Param, Result>();
        var result = f.Invoke(new Param("Parameter Executed"));
        result.Build();
    }
}

public static class DynamicFunctions
{
    public static Func<R> New<R>(this Type type)
    {
        if (!typeof(R).IsAssignableFrom(type))
        {
            throw new ArgumentException();
        }
        var dm = BuildNewMethod(type, Type.EmptyTypes);
        return (Func<R>)dm.CreateDelegate(typeof(Func<R>));
    }

    public static Func<T, R> New<T, R>(this Type type)
    {
        if (!typeof(R).IsAssignableFrom(type))
        {
            throw new ArgumentException();
        }
        var dm = BuildNewMethod(type, new Type[] { typeof(T) });
        return (Func<T, R>)dm.CreateDelegate(typeof(Func<T, R>));
    }

    private static DynamicMethod BuildNewMethod(Type newObjType, Type[] parameterTypes)
    {
        var dm = new DynamicMethod("New_" + newObjType.FullName, newObjType, parameterTypes, newObjType);
        var info = newObjType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, parameterTypes, new ParameterModifier[0]);
        ILGenerator il = dm.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Newobj, info);
        il.Emit(OpCodes.Ret);
        return dm;
    }
}

public class Result
{
    private Param _param;

    private Result()
    {
        Console.WriteLine("Parameterless constructor called");
    }

    private Result(Param param)
    {
        Console.WriteLine("Parametered constructor called");
        _param = param;
    }

    public void Build()
    {
        _param.Execute();
    }
}

public class Param
{
    private string _s;

    public Param(string s)
    {
        _s = s;
    }

    public void Execute()
    {
        Console.WriteLine(_s);
    }
}

}

1 Ответ

3 голосов
/ 07 апреля 2010
il.Emit(OpCodes.Ldarg_0); // <-- problem here

Поскольку ваш динамический метод не имеет параметров в версии New<T>, вы не можете использовать Ldarg_0. Кроме того, Newobj будет ожидать ноль аргументов, поэтому ваш стек не сбалансирован.

...