Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register callbacks from different classes

For a standard Request Server I use the below code to match a request to a service and process the incoming requests.

ServiceProvider

public class ServiceProvider
{
    public ServiceProvider()
    {
        Services = new Dictionary<Type, IService>
        {
            { typeof(FooRequest), new FooService() },
            { typeof(BarRequest), new BarService() },
        };
    }

    protected void OnRequestReceived(object request)
    {
        Services[request.GetType()].Process(request);
    }
}

FooService

public class FooService : IService
{
    public object Process(object request)
    {
        // Process request
    }
}

This works like a charm, but I want to get rid of one method (Process) per service. I tried working with Actions and Delegates but I somehow cannot accomplish this simple structure.

Basically my question is: How can I register multiple methods/callbacks from another class and store them in a dictionary for whenever I need to call them?

Desired result (pseudocode):

ServiceProvider

public class ServiceProvider
{
    public ServiceProvider()
    {
        var fooService = new FooService();
        var barService = new BarService();

        Handlers = new Dictionary<Type, Action>
        {
            { typeof(FooRequestA), fooService.ProcessA },
            { typeof(FooRequestB), fooService.ProcessB },
            { typeof(BarRequest), barService.Process },
        };
    }

    protected void ProcessRequest(object request)
    {
        Handlers[request.GetType()].Invoke(request);
    }
}

FooService

public class FooService
{
    public object ProcessA(FooRequestA request)
    {
        // Process request A
    }

    public object ProcessB(FooRequestB request)
    {
        // Process request B
    }
}

Improvement on solution

Using the below method you can simplify the recurring request-service matching code:

public void RegisterHandler<TRequest>(Action<TRequest> function)
{
    Handlers.Add(typeof(TRequest), request => function.Invoke((TRequest) request));
}

Which results in a very clean usage:

RegisterHandler<FooRequestA>(request => fooService.ProcessA(request));
like image 876
Christiaan Wevers Avatar asked Jun 12 '26 14:06

Christiaan Wevers


1 Answers

This is the best I can come up with. (while trying to stay close what you asked for... there may be much better ways to achieve what you actually want to do). I think you lose a little type safety with that solution:

FooService

public class FooService
{
    public object ProcessA(FooRequestA request)
    {
        return null;
    }
    public object ProcessB(FooRequestB request)
    {
        return null;
    }
}

BarService

public class BarService
{
    public void Process(BarRequest request)
    { }
}

ServiceProvider

public class ServiceProvider
{
    private readonly Dictionary<Type, Action<object>> Handlers;
    public ServiceProvider()
    {
        var fooService = new FooService();
        var barService = new BarService();

        Handlers = new Dictionary<Type, Action<object>>
        {
            {typeof(FooRequestA), request => fooService.ProcessA((FooRequestA)request)},
            {typeof(FooRequestB), request => fooService.ProcessB((FooRequestB)request)},
            {typeof(BarRequest), request => barService.Process((BarRequest)request)}
        };
    }

    protected void ProcessRequest(object request)
    {
        Handlers[request.GetType()].Invoke(request);
    }
}

Since you cannot convert a method group (like fooService.ProcessA) into an Action, you need to add lambdas to your Dictionary<Type, Action<object>> and provide the request as parameter.

like image 65
René Vogt Avatar answered Jun 15 '26 04:06

René Vogt