Cannot convert method group to non-delegate type with reflection

Viewed 2931

I'm attempting to automatically register request handling classes with reflection.

This is an example of manually adding a handler for execution of a certain request.

// generic manual method of registration
server.RegisterHandler<GetData>(base.ExecuteMessage);

Here is the attempt to register with reflection. The invoke method will not accept the 'ExecuteMessage' method getting the error "Error CS0428 Cannot convert method group 'ExecuteMessage' to non-delegate type 'object'. Did you intend to invoke the method?".

// registration with reflection
foreach (var type in serviceTypes)
{
    // registerHandlerMethod definition:    RegisterHandler<T>(Func<IMessage<T>, object> processMessageFn)
    // ExecuteMessage definition:           object ExecuteMessage(IMessage message)

    registerHandlerMethod.MakeGenericMethod(type).Invoke(server, new object[] { base.ExecuteMessage });
}

Is it possible to cast the ExecuteMessage method in any way to get this to work?

Edit: Added example with problem below

class Program
{
    static void Main(string[] args)
    {
        var server = new Server();

        // generic manual method of registration
        server.RegisterHandler<GetData>(ExecuteMessage);

        // registration with reflection
        var serviceTypes = new List<Type> { typeof(GetData) };
        var registerHandlerMethod = typeof(Server).GetMethod(nameof(Server.RegisterHandler));

        foreach (var type in serviceTypes)
        {
            registerHandlerMethod.MakeGenericMethod(type).Invoke(server, new object[] { ExecuteMessage });
        }
    }

    static object ExecuteMessage(IMessage message)
    {
        return null;
    }

    internal class GetData
    {

    }

    internal interface IMessage<T> : IMessage
    {

    }

    internal interface IMessage
    {

    }

    internal class Server
    {

        internal void RegisterHandler<T>(Func<IMessage<T>, object> processMessageFn)
        {
        }
    }
}
1 Answers

The reason for "Cannot convert method group..." is because the compiler doesn't know the type of the delegate to convert it to.

You need to call the Func constructor with reflection as well. This is complicated by the fact that IMessage is generic also.

You also need to redefine ExecuteMessage as generic to match the delegate type:

static object ExecuteMessage<T>(IMessage<T> message)
{
    return null;
}

I think the code you need is as follows:

var executeMethod = typeof(Program).GetMethod(nameof(ExecuteMessage), BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var type in serviceTypes)
{
    var messageType = typeof(IMessage<>).MakeGenericType(type);
    var funcType = typeof(Func<,>).MakeGenericType(messageType, typeof(object));
    var func = executeMethod.MakeGenericMethod(type).CreateDelegate(funcType, this);  // don't pass this for static methods
    registerHandlerMethod.MakeGenericMethod(type).Invoke(server, new object[] { func });
}
Related