Autofac处理订单

时间:2016-10-05 09:09:33

标签: c# .net autofac

我开始在我的一个项目中使用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>();
        }
    }
}

1 个答案:

答案 0 :(得分:4)

你是对的,每个一次性组件都按照它们创建的相反顺序进行处理。

每个ILifetimeScope都有一个IDisposerdisposer.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);
}

IDisposerdisposer.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。请参阅ActivateInstanceLookup.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;
}