Skip to content

When a delegate is created from a DynamicMethod, the Method property returns a MethodInfo which does not implement CreateDelegate #78365

@nike4613

Description

@nike4613

Description

When a delegate is created from a DynamicMethod, the Method property of the resulting delegate returns a MethodInfo which does not implement CreateDelegate, leading to a NotSupportedException.

DynamicMethod's CreateDelegate implementation sets the Method property of the delegate to the DynamicMethod's RTMethodInfo object, which does not implement CreateDelegate itself. This causes problems when trying to, say, convert a delegate from one type to another type with an identical signature.

The project this was found in has for a long time has a CastDelegate helper to do exactly that. It works flawlessly in all other scenarios, including on Mono (using the Mono BCL).

Reproduction Steps

using System.Reflection.Emit;

// CastDelegate works for normal delegates
A a = () => Console.WriteLine("A");
var b = (B)CastDelegate(a, typeof(B));

a();
b();

// now lets try the same thing with a DynamicMethod
{
    var dm = new DynamicMethod("dm1", typeof(void), null);
    var il = dm.GetILGenerator();
    il.Emit(OpCodes.Ret);

    a = (A)dm.CreateDelegate(typeof(A));
}

// This invocation will throw System.NotSupportedException
b = (B)CastDelegate(a, typeof(B));

a();
b();

static Delegate CastDelegate(Delegate del, Type delType)
{
    var invokeList = del.GetInvocationList();
    if (invokeList.Length == 1)
        return invokeList[0].Method.CreateDelegate(delType, invokeList[0].Target);
    for (var i = 0; i < invokeList.Length; i++)
    {
        invokeList[i] = CastDelegate(invokeList[i], delType);
    }
    return Delegate.Combine(invokeList)!;
}

delegate void A();
delegate void B();

Expected behavior

No exception, and a delegate created just as if it were called on the original DynamicMethod.

Actual behavior

When the delegate was created from a DynamicMethod, CreateDelegate throws an exception even when the call would otherwise be valid.

Regression?

No response

Known Workarounds

It is possible to reflect into the RTMethodInfo to get the DynamicMethod reference back and call CreateDelegate on that.

Configuration

This has been tested on .NET 5, 6, and 7, but likely exists on all versions of .NET Core and likely Framework.

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions