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));
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With