Unity 2.0和处理IDisposable类型(特别是使用PerThreadLifetimeManager)

Lad*_*nka 40 .net c# idisposable inversion-of-control unity-container

我知道类似的问题被多次询问(例如:这里,这里,这里这里),但它是针对Unity的早期版本,其答案取决于使用的LifetimeManager类.

文件说:

Unity使用从LifetimeManager基类继承的特定类型(统称为生命周期管理器)来控制它如何存储对对象实例的引用以及容器如何处理这些实例.

好的,听起来不错所以我决定检查生命周期管理器中的构建实现.我的结论:

  • TransientLifetimeManager - 没有处理处理.Container仅解析实例,并且不会跟踪它.调用代码负责处理实例.
  • ContainerControlledLifetimeManager - 处理终身经理时的实例(=处置容器时).提供在层次结构中的所有容器之间共享的单例实例.
  • HierarchicalLifetimeManager- 从中获取行为ContainerControlledLifetimeManager.它在hiearchy(子容器)中为每个容器提供"单例"实例.
  • ExternallyControlledLifetimeManager - 没有处理处理.正确的行为,因为容器不是实例的所有者.
  • PerResolveLifetimeManager - 没有处理处理.它通常是相同的,TransientLifetimeManager但它允许在解析整个对象图时重用实例来进行依赖注入.
  • PerThreadLifetimeManager - 没有处理处理,如MSDN中所述.谁负责处置?

内置的实现PerThreadLifetimeManager是:

public class PerThreadLifetimeManager : LifetimeManager
{
    private readonly Guid key = Guid.NewGuid();
    [ThreadStatic]
    private static Dictionary<Guid, object> values;

    private static void EnsureValues()
    {
        if (values == null)
        {
            values = new Dictionary<Guid, object>();
        }
    }

    public override object GetValue()
    {
        object result;
        EnsureValues();
        values.TryGetValue(this.key, out result);
        return result;
    }

    public override void RemoveValue()
    { }

    public override void SetValue(object newValue)
    {
        EnsureValues();
        values[this.key] = newValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,处置容器不会处置使用此生命周期管理器创建的一次性实例.线程完成也不会处置这些实例.那么谁负责发布实例?

我试图在代码中手动处理已解析的实例,我发现了另一个问题.我无法拆除这个机构.生命周期管理器的RemoveValue是空的 - 一旦创建实例,就不可能从线程静态字典中删除它(我也怀疑该TearDown方法什么都不做).因此,如果Resolve在处置实例后调用,您将获得处置实例.我认为将此生命周期管理器与线程池中的线程一起使用时,这可能是一个很大的问题.

如何正确使用这个终身经理?

此外,此实现通常在自定义生命周期管理器中重用,如PerCallContext,PerHttpRequest,PerAspNetSession,PerWcfCall等.只有线程静态字典被其他一些构造替换.

我也理解正确处理一次性物品取决于终身经理吗?因此应用程序代码依赖于使用过的生命周期管理器

我读到在其他IoC容器中处理临时一次性对象是由子容器处理但我没有找到Unity的例子 - 它可能可能用本地范围的子容器处理,HiearchicalLifetimeManager但我不知道如何做.

小智 6

Unity只会处理一个实例.它真的不受支持.我的解决方案是实现此目的的自定义扩展 - http://www.neovolve.com/2010/06/18/unity-extension-for-disposing-build-trees-on-teardown/


Gar*_*ian 2

查看 Unity 2.0 源代码,感觉 LifetimeManager 被用来以不同的方式将对象保留在范围内,这样垃圾收集器就不会删除它们。例如,对于 PerThreadLifetimeManager,它将使用 ThreadStatic 来保存具有该特定线程生命周期的每个对象的引用。但是,在容器被 Dispose 之前,它不会调用 Dispose。

有一个 LifetimeContainer 对象,用于保存所有创建的实例,然后在 UnityContainer 被 Dispose 时被 Dispose(反过来,按时间倒序 Dispose 中的所有 IDisposable)。

编辑:经过仔细检查,LifetimeContainer 仅包含 LifetimeManager(因此称为“Lifetime”Container)。因此,当它被处置时,它只处置生命周期管理器。(我们面临已经讨论过的问题)。