来自 DI 容器 .Net Core 的实现工厂方法中的对象

Are objects from an implementation factory method disposed by the DI container .Net Core

当我使用显式 implementationFactory 注册接口的实现时,如下所示:

services.AddTransient<IDbConnection>(_ => new SqlConnection(connectionString));

实现在请求时初始化,在 DI 容器超出范围时释放。

但是当我这样做时,SqlConnection 是否也会被 DI 容器处理:

services.AddTransient<IRepository>(_ => new Repository(new SqlConnection(connectionString)));

intellisense 没有警告我有关实现 IDisposable 的未处置对象,但我认为这是不对的。

不,容器不会在第二种情况下处理,因为它对这个手动创建的实例一无所知:

class MyDisposable : IDisposable
{
    public bool Disposed { get; private set; }
    public void Dispose()
    {
        Disposed = true;
    }
}

class Container
{
    public Container(MyDisposable d)
    {
        Disposable = d;
    }
    public MyDisposable Disposable { get; private set; }
}

var col = new ServiceCollection();
col.AddTransient<MyDisposable>(_ => new MyDisposable());
col.AddTransient<Container>(s => new Container(new MyDisposable()));

Container container;
MyDisposable disposable;
using(var scope = col.BuildServiceProvider().CreateScope())
{
    container = scope.ServiceProvider.GetRequiredService<Container>();
    disposable = scope.ServiceProvider.GetRequiredService<MyDisposable>();
}
Console.WriteLine(disposable.Disposed); // true
Console.WriteLine(container.Disposable.Disposed); // false

但是如果你把二次注册改成:

col.AddTransient<Container>(s => new Container(s.GetRequiredService<MyDisposable>()));

两个 MyDisposable 都将被处理掉。

例如,使用 [Autofac][1],您可以解析当前生命周期范围并安排手动创建的实例以在该范围结束时进行处置:

var builder = new ContainerBuilder();
builder.Register(_ => new MyDisposable()).InstancePerDependency();
builder.Register(ctx => 
{
    var scope = ctx.Resolve<ILifetimeScope>();
    var dep = new MyDisposable();
    scope.Disposer.AddInstanceForDisposal(dep);
    return new Container(dep);
})
.InstancePerDependency();

Container container;
MyDisposable disposable;
using(var scope = builder.Build().BeginLifetimeScope())
{
    container = scope.Resolve<Container>();
    disposable = scope.Resolve<MyDisposable>();
}

Console.WriteLine(disposable.Disposed); // true
Console.WriteLine(container.Disposable.Disposed);  // true