JIT Compiler error - Invalid Program Exception using Reflection.Emit
Can someone explain to me why the following works for the first test but throws an InvalidProgramException for the second test? I'm stumped.
using System;
using System.Reflection;
using System.Reflection.Emit;
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();
}
}
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();
}
}
publi开发者_JAVA百科c 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);
}
}
}
il.Emit(OpCodes.Ldarg_0); // <-- problem here
Since your dynamic method doesn't have parameters in the New<T>
version, you can't use Ldarg_0
. Also, Newobj
will expect zero arguments, so your stack is unbalanced.
精彩评论