gpt4 book ai didi

c# - Autofac 处理命令

转载 作者:太空狗 更新时间:2023-10-29 23:20:43 25 4
gpt4 key购买 nike

我开始在我的一个项目中使用 Autofac 进行 DI,有一件事我无法从文档/谷歌搜索中弄清楚(也许我遗漏了什么)。

根据 documentation ,当容器(或 LifetimeScope)被释放时,Autofac 会自动释放所有在此容器/范围内解析的 Disposable 实例。

问题是:这些实例是否按某种特定顺序处理(官方保证)?

如果某些 Client 实例被注入(inject)了对 Service 实例的引用,那么似乎很自然地期望该 Client 应该被释放服务之前。 (假设依赖图没有循环引用,并且可以正确定义这样的顺序)。

如果这不是真的,并且依赖图节点可能以任意顺序处理,这意味着我必须在组件实现中采取一些额外的预防措施,以便每个组件在其某些依赖项突然失效时能够正常运行.这让生活变得更加艰难。

我做了一组简单的测试,在(几乎)所有情况下,处置顺序确实是“自然”的。

我还浏览了 Autofac 源代码,发现所有自动处理实例都存储在内部堆栈中,并以 pop() 顺序处理(即与存储顺序相反),这让我相信一些特定的处置命令实际上是强制执行的。

有人可以对此发表评论吗?谢谢。

编辑 当我尝试使用 PropertiesAutowired() 进行属性注入(inject)时,违反了“自然”处理顺序(通过 Hook OnActivated 事件)。以下代码:

class Service : IDisposable
{
public Service()
{
Console.WriteLine("Service.ctor()");
}

public void Dispose()
{
Console.WriteLine("Service.Dispose()");
}
}

class Client : IDisposable
{
public Service Service { get; set; }

public Client()
{
Console.WriteLine("Client.ctor()");
}

public void Dispose()
{
Console.WriteLine("Client.Dispose()");
}
}


class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Service>();
builder.RegisterType<Client>().PropertiesAutowired();
using (var container = builder.Build())
{
var clientProp = container.Resolve<Client>();
}
}
}

产生以下输出:

Client.ctor()
Service.ctor()
Service.Dispose()
Client.Dispose()

最佳答案

你是对的,每个一次性组件的处理顺序与它们创建的顺序相反。

每个ILifetimeScope有一个IDisposer ( disposer.cs ) 跟踪所有 IDisposable 实例的实例其范围内的对象。

/// <summary>
/// Provided on an object that will dispose of other objects when it is
/// itself disposed.
/// </summary>
public interface IDisposer : IDisposable
{
/// <summary>
/// Adds an object to the disposer. When the disposer is
/// disposed, so will the object be.
/// </summary>
/// <param name="instance">The instance.</param>
void AddInstanceForDisposal(IDisposable instance);
}

IDisposer 的默认实现( disposer.cs ) 使用 Stack<IDisposable> , Dispose方法由 Dispose 调用ILifetimeScope 的方法并“弹出”堆栈。

/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing">
/// <c>true</c> to release both managed and unmanaged resources;
/// <c>false</c> to release only unmanaged resources.
/// </param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
lock (_synchRoot)
{
while (_items.Count > 0)
{
var item = _items.Pop();
item.Dispose();
}
_items = null;
}
}
base.Dispose(disposing);
}

AddInstanceForDisposal在组件实例化之后调用。查看 Activate InstanceLookup 的方法( InstanceLookup.cs ]

private object Activate(IEnumerable<Parameter> parameters)
{
ComponentRegistration.RaisePreparing(this, ref parameters);

try
{
_newInstance = ComponentRegistration.Activator.ActivateInstance(this, parameters);
}
catch (Exception ex)
{
throw new DependencyResolutionException(ex);
}

if (ComponentRegistration.Ownership == InstanceOwnership.OwnedByLifetimeScope)
{
// The fact this adds instances for disposal agnostic of the activator is
// important. The ProvidedInstanceActivator will NOT dispose of the provided
// instance once the instance has been activated - assuming that it will be
// done during the lifetime scope's Disposer executing.
var instanceAsDisposable = _newInstance as IDisposable;
if (instanceAsDisposable != null)
_activationScope.Disposer.AddInstanceForDisposal(instanceAsDisposable);
}

ComponentRegistration.RaiseActivating(this, parameters, ref _newInstance);

return _newInstance;
}

关于c# - Autofac 处理命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39869810/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com