注册来自不同类的回调
本文关键字:回调 同类 注册 | 更新日期: 2023-09-27 18:34:37
对于标准请求服务器,我使用以下代码将请求与服务匹配并处理传入的请求。
服务提供商
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);
}
}
福服务
public class FooService : IService
{
public object Process(object request)
{
// Process request
}
}
这就像一个魅力,但我想摆脱每个服务的一个方法(进程(。我尝试使用操作和委托,但不知何故无法完成这个简单的结构。
基本上我的问题是:如何从另一个类注册多个方法/回调并将它们存储在字典中,以便在我需要调用它们时?
期望的结果(伪代码(:
服务提供商
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);
}
}
福服务
public class FooService
{
public object ProcessA(FooRequestA request)
{
// Process request A
}
public object ProcessB(FooRequestB request)
{
// Process request B
}
}
解决方案的改进
使用以下方法,您可以简化重复的请求-服务匹配代码:
public void RegisterHandler<TRequest>(Action<TRequest> function)
{
Handlers.Add(typeof(TRequest), request => function.Invoke((TRequest) request));
}
这导致了非常干净的使用:
RegisterHandler<FooRequestA>(request => fooService.ProcessA(request));
能想到的最好的。(在试图保持接近你要求的东西时...可能有更好的方法来实现你真正想做的事情(。我认为该解决方案会失去一点类型安全性:
福服务
public class FooService
{
public object ProcessA(FooRequestA request)
{
return null;
}
public object ProcessB(FooRequestB request)
{
return null;
}
}
酒吧服务
public class BarService
{
public void Process(BarRequest request)
{ }
}
服务提供商
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);
}
}
由于您无法将方法组(如fooService.ProcessA
(转换为Action
,因此您需要将lambda添加到Dictionary<Type, Action<object>>
中,并将请求作为参数提供。
由于您将字典声明为 <Type, Action>
,因此不能将参数传递给.Invoke(object)
方法 - Action
不接受任何参数。您可能需要的是Dictionary<Type, Action<object>>
.我说"可能"是因为ProcessA
和ProcessB
方法返回object
,所以Dictionary<Type, Func<object, object>>
似乎更合乎逻辑。无论如何,我希望这只是一个教育问题,因为还有其他方法可以更正确,更有效地完成您的需求。
除了在ServiceProvider
中注册单个方法,您还可以让服务决定它们可以处理哪些请求。您可以创建一个包含以下方法的接口(我使用 Request 作为所有请求的基类以避免使用 object
参数(:
public interface IService
{
bool CanHandle(Request request);
void Handle(Request request);
}
在注册表中,注册服务并将请求路由到服务:
public class ServiceProvider
{
private readonly IEnumerable<IService> _registeredServices = new IService[]
{
new FooService(),
new BarService();
};
protected void OnRequestReceived(Request request)
{
// Find first service that can handle the request
var serviceForRequest =
_registeredServices.Where(x => x.CanHandle(request)).FirstOrDefault();
if (serviceForRequest == null)
throw new InvalidOperationException("No service registered that can handle request " + request.ToString();
// Let the service handle the request
serviceForRequest.Handle(request);
}
}
此结构的优点是,您不必在每次服务可以处理新类型的请求时都更改ServiceProvider
。传输到示例中,可以将 ProcessB
方法添加到类中FooService
和更改CanHandle
和Handle
的实现,而无需更改注册。
您可以使用 IoC 容器或基于反射的实现动态检测它们,而不是注册服务。在这种情况下,即使您添加了新服务,也不必更改ServiceProvider
。