处置托管资源时的堆栈溢出

时间:2016-12-22 15:09:17

标签: c# .net unity-container stack-overflow idisposable

我有一个Unity IoC容器的简单包装器(临时使用Service Locator [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块时),会引发StackOverflowException。调试,看起来调用堆栈在:

之间重复
  • Dispose()在此课程中被调用
  • 在此课程中调用Dispose(true)
  • Dispose()
  • 上拨打IUnityContainer
  • 在此课程中调用Dispose()

enter image description here

我可以在这种情况下解决此问题:在类上放置一个bool标志,在Dispose()的第一行设置它,并在{{{{}}中检查它1}},所以递归在第二次迭代时结束。但是为什么会发生这种情况呢?我只能假设我错过了一些明显的或者误解了资源处理方面的事情。但是什么?

3 个答案:

答案 0 :(得分:4)

这是IDisposableUnityContainer的实施。很明显,您无法处置父容器。如果它们也是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(); 
   } 
} 

答案 1 :(得分:2)

我认为这里的问题是你不应该在你的类中处理实现IUnityContainer的容器实例。

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

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

答案 2 :(得分:2)

这可能不是最佳答案,但如果您无法控制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;
        }
}

create table test (col1 string, col2 int, col3 string)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES ("separatorChar" = ",","quoteChar" = "\"")
stored as textfile;