处理托管资源时堆栈溢出
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
。调试,看起来调用堆栈重复:
Dispose()
在此 class 上调用
- 在 class
上调用 Dispose(true)
- 在
IUnityContainer
上调用 Dispose()
- 在此 class
上调用 Dispose()
在这种情况下,我可以通过在 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;
}
}
这是 UnityContainer
中 IDisposable
的实现。很明显,您不能处置您的父容器。它将遍历所有注册并在它们也是 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();
}
}
我有一个简单的 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
。调试,看起来调用堆栈重复:
Dispose()
在此 class 上调用
- 在 class 上调用
- 在
IUnityContainer
上调用 - 在此 class 上调用
Dispose(true)
Dispose()
Dispose()
在这种情况下,我可以通过在 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;
}
}
这是 UnityContainer
中 IDisposable
的实现。很明显,您不能处置您的父容器。它将遍历所有注册并在它们也是 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();
}
}