C# 实现处置 - 为什么需要检查处置和处置?
C# Implementing Dispose - why need check disposing and disposed?
我搜索了一下,没有找到确切的答案。我正在学习 Implementing Dispose 的正确方法。我想知道为什么需要 2 个布尔值。
- 为什么需要处置?只有析构函数调用Dispose(false),为什么析构函数不强制释放托管资源?
- 为什么需要处置?如果此对象已被释放,如何调用 Dispose 方法?你能说出调用 Dispose 并且处置为真的场景吗?
disposing
布尔值用于指示从何处调用 Dispose
。它是通过 YourObject.Dispose
或 using
语句显式调用的,还是从终结器线程隐式调用的。
需要这种区分,因为当 Dispose
是来自终结器线程的 运行 时,无法保证任何托管对象在对象中仍然存在,因此限制了处置仅适用于该类型拥有的非托管资源。
disposed
布尔值用于标记该对象已被处置。比方说,确实处理了对象,但是缺少实现 GC.SuppressFinalize(this)
。即使对象已被释放,它仍然会 运行(再次)一旦它的终结器执行,并尝试再次释放那些非托管资源,它们已经被释放。
您提供的文档中的示例很好地解释了这一点:
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
disposed = true;
}
}
对于第二个问题:Dispose()
方法应该可以毫无问题地调用两次(参见 IDisposable.Dispose()
:
If an object's Dispose method is called more than once, the object must ignore all calls after the first one.The object must not throw an exception if its Dispose method is called multiple times.Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed.
一个常见的情况是,当一个 Stream
对象被传递给另一个 Stream
对象时,该对象需要 "ownership":
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms))
//using (var sw = new StreamWriter(zip, Encoding.UTF8, 4096, true))
{
}
// false: ms has already been disposed
bool canWrite = ms.CanWrite;
}
StreamWriter
通常拥有底层流的所有权(在本例中为 ms
),因此当 StreamWriter
的 Dispose()
被调用时, MemoryStream
的 Dispose()
... 但请注意,即使 MemoryStream
也在 using
块中,因此它的 Dispose()
将被再次调用。
这里没有问题,因为各种Stream
类的Dispose()
都正确实现了。如果你想避免这个双重 Dispose()
,几乎所有 Stream
类 都有一个重载,告诉他们是否必须获得基础 Stream
的所有权(见注释行...参数称为 leaveOpen
,因此通过将其设置为 true
,StreamWriter
不会 Dispose()
底层流)
我搜索了一下,没有找到确切的答案。我正在学习 Implementing Dispose 的正确方法。我想知道为什么需要 2 个布尔值。
- 为什么需要处置?只有析构函数调用Dispose(false),为什么析构函数不强制释放托管资源?
- 为什么需要处置?如果此对象已被释放,如何调用 Dispose 方法?你能说出调用 Dispose 并且处置为真的场景吗?
disposing
布尔值用于指示从何处调用 Dispose
。它是通过 YourObject.Dispose
或 using
语句显式调用的,还是从终结器线程隐式调用的。
需要这种区分,因为当 Dispose
是来自终结器线程的 运行 时,无法保证任何托管对象在对象中仍然存在,因此限制了处置仅适用于该类型拥有的非托管资源。
disposed
布尔值用于标记该对象已被处置。比方说,确实处理了对象,但是缺少实现 GC.SuppressFinalize(this)
。即使对象已被释放,它仍然会 运行(再次)一旦它的终结器执行,并尝试再次释放那些非托管资源,它们已经被释放。
您提供的文档中的示例很好地解释了这一点:
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
disposed = true;
}
}
对于第二个问题:Dispose()
方法应该可以毫无问题地调用两次(参见 IDisposable.Dispose()
:
If an object's Dispose method is called more than once, the object must ignore all calls after the first one.The object must not throw an exception if its Dispose method is called multiple times.Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed.
一个常见的情况是,当一个 Stream
对象被传递给另一个 Stream
对象时,该对象需要 "ownership":
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms))
//using (var sw = new StreamWriter(zip, Encoding.UTF8, 4096, true))
{
}
// false: ms has already been disposed
bool canWrite = ms.CanWrite;
}
StreamWriter
通常拥有底层流的所有权(在本例中为 ms
),因此当 StreamWriter
的 Dispose()
被调用时, MemoryStream
的 Dispose()
... 但请注意,即使 MemoryStream
也在 using
块中,因此它的 Dispose()
将被再次调用。
这里没有问题,因为各种Stream
类的Dispose()
都正确实现了。如果你想避免这个双重 Dispose()
,几乎所有 Stream
类 都有一个重载,告诉他们是否必须获得基础 Stream
的所有权(见注释行...参数称为 leaveOpen
,因此通过将其设置为 true
,StreamWriter
不会 Dispose()
底层流)