【发布时间】:2019-01-17 19:14:53
【问题描述】:
我有一个接口和它的多个实现:
interface IFoo { bool CanFoo(); }
class Foo1 : IFoo { bool CanFoo() => true; }
class Foo2 : IFoo { bool CanFoo() => false; }
我想在IServiceCollection 中注册所有这些并提供这样的自定义实现工厂:
services
.AddTransient<IFoo, Foo1>()
.AddTransient<IFoo, Foo2>();
// register the factory last
services.AddTransient<IFoo>(provider =>
{
var registrations = provider.GetServices<IFoo>(); // Exception
return registrations.FirstOrDefault(r => r.CanFoo());
};
所以你可能会看到这个想法是解决第一个可用的实现。然而,这段代码会导致StackOverflowException,因为provider.GetServices<IFoo>() 也尝试解析工厂,即使它没有实现接口,从而导致无限循环。
有几个问题:
- 在这种情况下是否期望服务提供商尝试解决工厂问题?
- 如果可能,我该如何克服这个问题?
更新
之所以首先涉及工厂,是因为必须在运行时根据输入数据选择正确的服务,这可能会随着每个新的请求而改变。因此,我无法将其缩小到应用程序启动期间的特定服务注册。
【问题讨论】:
-
GetServices 创建服务,它不返回他们的注册。当您调用它时,它将尝试通过实例化任何已注册的类型 和 工厂来创建服务。如果你在工厂内部调用它,你会得到一个递归调用
-
这段代码很奇怪。每次您想要一个
IFoo时,您是否要创建 N 个临时对象但只保留其中一个?看起来您正在尝试在 DI 中实现过滤。您要解决的实际问题是什么? -
@PanagiotisKanavos 正确,就是这样。我意识到它并不完美,但我需要将处理请求的能力委托给服务。有什么建议吗?
-
您可以通过
services而不是provider获取注册。您可以检查ServiceDescriptor 的每个IFoo的ServiceType,并在ImplementationTypes 上使用反射来查找它们中的哪些具有特定属性或实现其他“标记”接口。注册具体的类,Foo1,Foo2,而不是它们的接口,并使用工厂从服务描述符中选择你想要的 -
您想要使用的实际标准是什么?为什么要调用具体类的方法?
标签: c# asp.net-core .net-core