当我在两个相互依赖的
IDisposable
对象之间存在循环依赖并且也应该相互传播处理时,我应该如何最好地避免 StackOverflowException
方法中的无限递归?我最初的猜测是保存并检查对象是否已经在调用堆栈中调用了它的 Dispose()
方法并在这种情况下提前退出,就像我在示例实现中所做的那样:
Dispose()
虽然我在快速谷歌搜索中没有找到这样的实现,所以我想知道是否可以做,保存和一切都很好。
程序输出为:
using CircularDispose;
using JetBrains.Annotations;
Example a = new(nameof(a));
Example b = new(nameof(b));
a.Other = b;
b.Other = a;
Console.WriteLine("Start");
a.Dispose();
Console.WriteLine($"{nameof(a)} is disposed: {a.IsDisposed}");
Console.WriteLine($"{nameof(b)} is disposed: {b.IsDisposed}");
Console.WriteLine("Finished");
namespace CircularDispose
{
[PublicAPI]
public class Example : IDisposable
{
private bool _isDisposing;
private string _name;
public Example? Other { get; set; }
public bool IsDisposed { get; private set; }
public Example(string name) => _name = name;
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
private void Dispose(bool disposing)
{
Console.WriteLine($"{_name}.{nameof(Dispose)}({disposing}) was called");
if (!_isDisposing && !IsDisposed)
{
_isDisposing = true;
if (disposing)
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
IsDisposed = true;
}
}
~Example()
{
Dispose(false);
}
[PublicAPI]
protected virtual void DisposeUnmanagedResources()
{
// dispose unmanaged resources
}
[PublicAPI]
protected virtual void DisposeManagedResources()
{
Other?.Dispose();
Other = null;
}
}
}
Start
a.Dispose(True) was called
b.Dispose(True) was called
a.Dispose(True) was called
a is disposed: True
b is disposed: True
Finished
字段:
_isDisposing
如果内存消耗是一个问题(例如,因为您有很多
类的实例),一个技巧是重用 private void Dispose(bool disposing)
{
Console.WriteLine($"{_name}.{nameof(Dispose)}({disposing}) was called");
if (!IsDisposed)
{
IsDisposed = true;
if (disposing)
{
DisposeManagedResources();
}
DisposeUnmanagedResources();
}
}
部分中已经使用的现有变量,例如您的
DisposeManagedResources()
变量案件。如果它为 null,则 Dispose 已被调用(或没有必要)。 Other
永远不应该是循环的,因为那样你会接触到一些不是非托管资源的东西,所以它也可能在 DisposeUnmanagedResources()
.之外