【发布时间】:2020-05-13 16:28:14
【问题描述】:
我在 Net Core 3 控制台应用程序中有一个工厂类,它需要能够在运行时针对 DI 容器进行解析:
public class OptionFactory : IOptionFactory
{
private readonly IServiceProvider _svcProvider;
public OptionFactory( IServiceProvider svcProvider )
{
_svcProvider = svcProvider;
}
public IOption<T>? CreateOption<T>( params string[] keys )
{
// code eliminated for brevity
try
{
return retVal = _svcProvider.GetRequiredService<Option<T>>();
}
catch( Exception e )
{
return null;
}
}
}
我正在使用 Autofac 定义 DI 容器,然后在提供程序类中通过 new AutofacServiceProvider( builder.Build() ) 将其“分配”给 IServiceProvider:
public class TestServiceProvider
{
public static IServiceProvider Instance { get; private set; }
static TestServiceProvider()
{
var builder = new ContainerBuilder();
builder.RegisterType<OptionFactory>()
.As<IOptionFactory>()
.SingleInstance();
// code omitted for brevity
Instance = new AutofacServiceProvider( builder.Build() );
}
}
我不清楚如何将IServiceProvider 本身注册到 DI 容器中,以便可以将其注入构造函数中。这甚至可能吗?这似乎有点自我参照,这可能是有问题的。
我在网上看到的所有示例都要求引用 Autofac IContainer 本身(或在我的示例中为 TestServiceProvider.Instance)。我可以这样做,但它最终会将我的库与具体的服务提供者类联系起来。如果可以的话,我想我想避免。
我意识到注入 IServiceProvider 被一些/许多人认为是一种反模式,尽管其他人认为它在工厂类中是可以接受的,因为工厂“只是”扩展了 DI 容器。我对不依赖工厂类的其他方法持开放态度,只要它们允许我在运行时创建开放泛型类型的具体实例。
【问题讨论】:
-
如果您还没有这样做,并且在您的工厂有要注入的 IEnumerable
。您可以收集实例并返回与您的方法匹配的实例。 -
关于碰撞的好点,我会解决的。 IEnumerable 方法会起作用——我经常使用它——但它需要(我认为)在初始化 IContainer 时知道可能的派生泛型类型。我宁愿不必提前指定那些(这是我正在尝试做的即时性质的另一个方面)。感谢您的反馈!
-
这就是为什么我提出了基本 IOption 接口的想法,因此您可以在不指定实际派生类型的情况下解决所有这些问题。这是一个标记界面,只是为了帮助您将它们全部收集起来
-
有这个想法的一篇很棒的博文在这里:stevejgordon.co.uk/…(顺便说一句,史蒂夫·戈登的内容很棒)
标签: c# dependency-injection autofac