开发者

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 strings, 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜