0

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

Aserian
  • 1,047
  • 1
  • 15
  • 31
  • 1
    Create the delegate as if it's a static function, this is called an open instance delegate, see https://stackoverflow.com/questions/951624/how-to-create-a-delegate-to-an-instance-method-with-a-null-target – Charlieface Feb 24 '21 at 00:56
  • 1
    Just putting it out there, In the time it has taken you to ponder the solution and write the question. You could have likely refactored the code to do it correctly instead of implement an epicycle via a reflection hack. It would be a breaking change yeah, though show in the error list (even if its a nuget dependency), which you could just work through... Sometimes taking a little more time to do things the right way, actually saves you time, leaving less hacks and better more ubiquitous code base. Anyway, im sure you know this, good luck – TheGeneral Feb 24 '21 at 01:04
  • @00110001 I think that offering suggestions as to what the "right" way is, is part of the reason behind why this forum exists. While I can appreciate there is probably a better way to do this, I don't think I'd be here asking questions if I already knew what it was. – Aserian Feb 24 '21 at 03:51
  • 1
    @Aserian I mean, "*My issue is that I cannot change the client's version of "RegHandler" since too many legacy components rely on it*" , my suggestion is just bite the bullet and make the change if it at all you can – TheGeneral Feb 24 '21 at 04:15

0 Answers0