我开始在我的一个项目中使用Autofac进行DI,有一件事我无法从文档/谷歌搜索中得到清楚(也许我错过了一些东西)。
根据documentation,当处置容器(或LifetimeScope)时,Autofac会自动处理在此容器/范围内解析的所有Disposable实例。
问题是:这些实例是按某种特定顺序处理的(官方保证)?
如果某个PortletSession
实例注入了对Client
个实例的引用,那么Service
应该在之前被置于之前。 Client
。 (假设依赖图没有循环引用,可以正确定义这样的顺序)。
如果不是这样,并且依赖图节点可以按任意顺序排列,则意味着我必须在组件实现中采取一些额外的预防措施,以便每个组件在其某些依赖关系突然变为死时都能正常运行。这使生活更加艰难。
我进行了一系列简单的测试,在(几乎)所有场景中,处理的顺序确实是"自然"之一。
我还浏览了Autofac源代码,发现所有自动一次性实例都存储在堆栈内部,并以pop()顺序处理(即反向商店的oder),这让我相信一些具体的处置令实际上是强制执行的。
有人可以对此发表评论吗?谢谢。
编辑违反"自然"当我尝试使用Service
(通过挂钩PropertiesAutowired()
事件工作)进行属性注入时,会发生处理订单。以下代码:
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>();
}
}
}
答案 0 :(得分:4)
你是对的,每个一次性组件都按照它们创建的相反顺序进行处理。
每个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.cs]
InstanceLookup
方法
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;
}