Why does calling a DynamicMethod with an instance of my own class cause an exception?
I'm learning CIL by making my own functions at runtime with Reflection.Emit
. I'm actually surprised how easy things have been up until now but I've hit something that I can't guess my way through and I can't find anything relative in the docs.
I'm trying to create a function that simply prints a very simple class I have defined. If I change my code to print string
s, say, it works but it always fails to run when I pass an instance of my class A
.
What's weird is I can comment out my function body and it still fails with a TargetInvocationException
. It must be quite simple but I can't see what's up!
class A
{
public override strin开发者_JAVA百科g ToString()
{
return "AAA!";
}
}
class Program
{
static void Main(string[] args)
{
DynamicMethod func = new DynamicMethod("func", null, new Type[] { typeof(A) });
ILGenerator il = func.GetILGenerator();
//il.Emit(OpCodes.Ldarg_0);
//il.Emit(OpCodes.Box, typeof(A));
//il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(A) }));
il.Emit(OpCodes.Ret);
func.Invoke(null, new object[] { new A() });
Console.Read();
}
}
What am I doing so wrong to make this raise an exception? Why does this only happen with my classes?
It was quite silly actually. I spent several hours on this but when I followed Laurent Etiemble's advice and created a delegate the exception I got told me my class A wasn't public.
Solution: Add the public keyword before class A
. Works perfectly. I knew it had to be something insanely simple.
The problem is simple but not-obvious. For a start don't box the argument as already pointed out. But the real problem is the A class is not public. The default binding for the Invoke function you are using (rather than the full one) is to only find publicly methods. Because A is a non-public class it means it fails to find your function (amazing I know) and fails.
First - You shouldn't be emitting the Box
opcode since A
is a class and doesn't need to be boxed. Boxing is only for value types.
Second - The reason why it's failing is because the method doesn't have permission to access class A (it's not public). Either make A
public
OR You can instruct the JIT compiler to skip visibility checks by using this constructor and passing true
to the skipVisibility parameter.
精彩评论