mardi 23 février 2021

C# Reflectively call method without access to instantiated type

I am working on a code base that offers a command to a message handler to intercept messages of a certain type.

The register function looks like this:

RegHandler<T>(Func<T, IMessageMetaData, Task> handler) where T : IMessage

I am looking to add some common functionality in how messages are preprocessed by creating an abstract class that does catches the messages that are forwarded from this function to the registering function. The base class will implement it's own "RegHandler" that keeps track of type/func<IMessage, IMessageMetaData, Task>. Then it will implement a

Task MsgHandler(IMessage, IMessageMetaData)

function which I will register as the handler for all types of inheriting classes.

Classes can inherit from this and flag their message handlers with an attribute. I will reflectively iterate the instantiated child class to to find the methods with the specified attribute and

  1. Register the Type/Function with the base class function, "RegHandler"
  2. Register the base class handler with the client as the handler to intercept this message (client.Register(childClass.MsgHandler)

In this way, the client should direct every message that is registered by inheriting classes to base class handler "MsgHandler", MsgHandler will do it's preprocessing then call the method implemented by the inheriting class so that it can do what it needs to do.

The normal way a class would call the RegHandler method is like this:

public class ClassWithHandler
{
    public async Task MyMessageHandler(MyMessageType message, IMessageMetatData) : where MyMessageType : IMessage
    {

    }
}

ClassWithHandler cwh = new ClassWithHandler();
client.RegHandler(cwh.MyMessageHandler);

I have seen this answer: https://stackoverflow.com/a/2933227/4089216 which shows how to call the method when you have access to the object, but it also includes the object in the call itself (i.e. Func<ClassWithHandler, IMessage, IMessageMetaData, Task>).

My issue is that I cannot change the client's version of "RegHandler" since too many legacy components rely on it, nor add functionality to the class to keep track of the instantiated class that owns the handler in order to reflectively call the method like the above.

Therefore I need to convert a MethodInfo (having access to the instantiated object) into a Func<IMessage, IMessageMetaData, Task> instead of the above method that would give me Func<ClassWithHandler, IMessage, IMessageMetaData, Task>. Is there a way to get the reference in the format that the RegHandler requires using reflection?

Thanks for your time, please let me know if you need more info





Aucun commentaire:

Enregistrer un commentaire