我刚刚偶然发现了一个以前没有遇到过的依赖注入问题.DI的概念和它的优点对我来说非常清楚,我在我的项目中使用了构造函数注入.所以DI容器为构造函数所需的接口创建类,我可以使用它们而不用考虑它背后的具体实现.如果类实现了IDisposable,则当它超出作用域(注册为类型)或容器本身被释放时(注册为单例),它会被容器释放.使用此接口实例的类不需要知道.我喜欢.太好了!

但一旦我注入一家这样的工厂并投入使用,这些假设就不再成立.

public class SomeClass(Func<ISomeDisposeableInterface> factory)
{
    var x = factory();

    //or even
    using (var x = factory())
    {...}
}

当实例超出范围时,不调用Dispose.我的意思是,它当然不会.DI容器不能知道我正在对创建的实例做什么.如果对该工厂创建的实例调用Dispose(),或者将其放在Using块中,我现在必须知道它是否注册为单例,否则将出现异常.这似乎与整个概念不符.

问题:

  1. 我是不是理解了DI概念中的错误?
  2. 使用这样的工厂被认为是反模式吗?
  3. 有没有其他方法可以在类中生成不与DI概念冲突的"SomeDisposeableInterface"的新实例?

亲切的问候!

推荐答案

我是不是理解了DI概念中的错误?

不,但它更多的是关于依赖注入实现,而不是一个概念本身.在内置DI容器的情况下,它将只处理它创建的OF类型(参见文档的Disposal of services部分).因此,处置的需要取决于工厂是如何实施的.在.NET 8的默认DI容器中引入Keyed DI services之前,非常常见的模式如下所示:

services.AddScoped<Func<SomeKeyType, ISomeDisposeableInterface>>(sp => key => key switch
{
    key1 => sp.GetRequiredService<SomeImpl1>(),
    key2 => sp.GetRequiredService<SomeImpl2>(),
});

这显然不需要手动处理依赖项.

使用这样的工厂被认为是反模式吗?

那得看情况.例如,EF Core使用相同的模式,由工厂创建的DbContext factory (IDbContextFactory)-DbContext个实例不由应用程序的服务Provider 管理,因此必须由应用程序处理.

是否有其他方法可以在类中生成"SomeDisposeableInterface"的新实例,而不会与DI概念冲突?

一般来说-是的.类似于前面的代码片段:

services.Add{Lifetime}<ISomeDisposeableInterface, SomeImpl>();
services.Add{Lifetime}<Func<ISomeDisposeableInterface>>(sp => () => sp.GetRequiredService<ISomeDisposeableInterface>());

但在实践中,这在很大程度上取决于工厂/服务的注册和使用方式.

再说一次--这实际上是实现细节.其他一些DI容器(参见Default service container replacement文档)在理论上可以有不同的行为(尽管在实践中我怀疑是否有任何容器可以拦截这样的东西),或者允许与作用域处置挂钩(我已经用Autofac做了类似的事情).

Csharp相关问答推荐

在实际上是List T的 IESEARCH上多次调用First()是否不好?

. NET Core DB vs JSON模型设计

用C#调用由缓冲区指针参数组成的C API

如何在C#中实现非抛出`MinBy`?

Docker Container中的HttpRequest后地址不可用

如何通过寻找向量长度来优化两个循环?

C#Null判断处理失败

如何在Cosmos SDK中控制超时、重试和重试之间的延迟?

当空判断结果赋给变量时,为什么会出现可能空异常警告的解引用?

为什么此名称不再被识别?名称不存在于当前上下文中?

ReadOnlyMemory访问基础索引的替代方案

Visual Studio 17.8.0制表符自动完成问题--三缩进

为什么在使用JsonDerivedType序列化泛型时缺少$type?

FakeItEasy自动嘲弄内容

如何保存具有多个重叠图片框的图片框?

如何对正方形格线进行对角分组

通过mini kube中的远程调试Pod与从emoteProcessPickerScript中解析错误输出的代码错误进行比较

使用ITfoxtec.Identity.Saml2解析相同键多值SAML 2声明

同时通过多个IEumable<;T&>枚举

无法停止PowerShell中的低级挂钩(c#挂钩)