2

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 string  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?

3 Answers3

1

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.

0

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.

Brandon Cuff
  • 1,438
  • 9
  • 24
0

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.

tyranid
  • 13,028
  • 1
  • 32
  • 34
  • I realized almost as you posted. Hence my answer is along the same lines. This is the right answer! –  Feb 08 '10 at 22:34
  • Gotta love reflection sometimes, almost never gives you sensible answers, especially when you try object or string and it works just because they are public, grr :) – tyranid Feb 08 '10 at 22:36