处理托管资源时堆栈溢出

Stack Overflow when Disposing a Managed Resource

我有一个简单的 Unity IoC 容器包装器(临时使用服务定位器 [anti-]Pattern 将 DI 引入遗留代码库),并且由于 Unity 中的 IUnityContainer 实现了 IDisposable 我也想通过包装器公开它。

包装器很简单:

public class IoCContainer : IIoCContainer
{
    private IUnityContainer _container;

    public IoCContainer(IUnityContainer container)
    {
        _container = container;
    }

    public T Resolve<T>()
    {
        return _container.Resolve<T>();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~IoCContainer()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
            if (_container != null)
            {
                _container.Dispose();
                _container = null;
            }
    }
}

IIoCContainer 是域接口,上面只有 T Resolve<T>(),当然还有 IDisposable。因此,该方法下面的所有内容都只是 IDisposable as I found it on MSDN.

的实现

但是,当在此对象上调用 .Dispose() 时(例如退出 using 块时),会引发 WhosebugException。调试,看起来调用堆栈重复:

在这种情况下,我可以通过在 class 上放置一个 bool 标志来解决这个 ,将其设置在 [=20= 的第一行],并在 Dispose(bool) 中检查它,因此递归在第二次迭代时结束。但是 为什么首先会发生这种情况? 我只能假设我错过了一些明显的事情或者误解了有关资源处理的事情。但是什么?

我认为这里的问题是您不应该在 class.

中处理实现 IUnityContainer 的容器实例

该实例作为资源传递给您的 class,但它是在外部创建的,因此创建该实例的任何代码都应该负责正确处理它。

您的 IoCContainer 应该只关心处理它在内部创建的资源。

这可能不是最好的答案,但是如果您无法控制 IUnityContainer 的实现并且 来处理 IoCContainer 您总是可以以至少两种有效的方式打破递归链:

protected virtual void Dispose(bool disposing)
{
    if (disposing)
        if (_container != null)
        {
            var tempContainer = _container;
            _container = null;
            tempContainer.Dispose();
        }
}

private bool isDisposed = false;
protected virtual void Dispose(bool disposing)
{
    if(isDisposed) return;
    isDisposed = true;

    if (disposing)
        if (_container != null)
        {
            _container.Dispose();
            _container = null;
        }
}

这是 UnityContainerIDisposable 的实现。很明显,您不能处置您的父容器。它将遍历所有注册并在它们也是 IDisposable 时处理它们。看看:

protected virtual void Dispose(bool disposing) 
{ 
   if (disposing) 
   { 
       if (lifetimeContainer != null) 
       { 
           lifetimeContainer.Dispose(); 
           lifetimeContainer = null; 

           if (parent != null && parent.lifetimeContainer != null) 
           { 
               parent.lifetimeContainer.Remove(this); 
           } 
       } 

       extensions.OfType<IDisposable>().ForEach(ex => ex.Dispose()); 
       extensions.Clear(); 
   } 
}