Search code examples
c#delegatesinvokesystem.reflectionreflection.emit

Why does `dynamicMethod.CreateDelegate(typeof(Action)).Method.Invoke(null,new object[0]);` throw an Exception?


This seems to work, providing a (weird) way to call an Action:

Action action = () => { };
action.Method.Invoke(action.Target, new object[0]);

This seems to work, providing a (helpful) way to create an Action:

var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
action();

However, this throws an Exception:

var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
action.Method.Invoke(action.Target, new object[0]);  // Throws exception

MethodInfo must be a runtime MethodInfo object.

Question: Why is the above code snippet throwing an Exception?


Working code example

var dynamicMethod = new System.Reflection.Emit.DynamicMethod(
            ""
        ,   typeof(void)
        ,   new Type[0]
    );

var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;

try
{
    action.Method.Invoke(action.Target, new object[0]);
}
catch (Exception exception)
{
    System.Console.WriteLine(exception);
}

This causes the Console to write:

Exception thrown: 'System.ArgumentException' in mscorlib.dll
System.ArgumentException: MethodInfo must be a runtime MethodInfo object.
Parameter name: this
  at System.Reflection.Emit.DynamicMethod.RTDynamicMethod.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
  [...]

Thoughts

I've tried a bunch of variations on calling action.Method.Invoke(), but all sorts of variations on the call arguments don't seem to change the exception-message,

MethodInfo must be a runtime MethodInfo object.

My guess is that action.Method isn't a "runtime MethodInfo", despite being a "MethodInfo". I'm not really sure what the distinction between a runtime-MethodInfo and a non-runtime-MethodInfo might be, though.


Solution

  • MethodInfo is an abstract type, which has several implementations.

    One of them is the internal type System.Reflection.RuntimeMethodInfo. This is what you get when you reflect the methods of existing runtime types:

    Console.WriteLine(typeof(object).GetMethod("ToString").GetType().FullName); // System.Reflection.RuntimeMethodInfo
    

    On the other hand, DynamicMethod.CreateDelegate uses another implementation of MethodInfo:

    Console.WriteLine(action.Method.GetType().FullName); // System.Reflection.Emit.DynamicMethod+RTDynamicMethod
    

    And it seems it does not support invocation by MethodInfo.Invoke.

    But if you cannot use the Invoke method of your created delegate for some reason (because you don't know the exact delegate type, for example), you still can use the Delegate.DynamicInvoke method (however, dynamic invocation of a delegate is almost as slow as the reflection API):

    Delegate del = action; // let's assume you don't know the delegate type
    del.DynamicInvoke(); // slow as hell but works without throwing an exception