IDisposable的实现是否可以安全地多次调用Dispose()?或者相反?大多数.NET Framework类采用什么方法?
具体来说,多次拨打System.Data.Linq.DataContext.Dispose()
是否安全?
我问的原因是因为我想知道是否需要这种额外保护:
public override void Dispose(bool disposing)
{
// Extra protection...
if (this.obj != null)
{
this.obj.Dispose();
this.obj = null;
}
// Versus simply...
this.obj.Dispose();
base.Dispose(disposing);
}
在处理类的IDisposable成员时,或者我是否应该只调用this.obj.Dispose()
而不关心它是否曾被调用过。
答案 0 :(得分:54)
你应该可以安全地多次调用它,但如果可以,你应该尽量避免使用它。
来自IDisposable.Dispose()
上的MSDN页面:
如果多次调用对象的Dispose方法,则该对象必须忽略第一个之后的所有调用。如果多次调用Dispose方法,则该对象不得抛出异常。
答案 1 :(得分:6)
是的,您的IDisposable.Dispose()实现应该容忍被多次调用。在第一次调用Dispose()之后,所有其他调用都可以立即返回。
我更喜欢你的代码示例的第一部分,在你去的时候处理和归零局部变量。
请注意,即使在代码中实现Dispose和null模式,也可能多次调用.Dispose()。如果多个使用者持有对同一个一次性对象的引用,则该对象的Dispose可能会被多次调用,因为这些对象删除了对它的引用。
答案 2 :(得分:2)
对象应该容忍Dispose被调用不止一次,因为 - 特别是在存在异常的情况下 - 清理代码可能很难确定哪些东西已被清理,哪些没有。在清除IDisposable字段时清除它们(并且容忍已经为空的字段)将使得更容易避免对Dispose的冗余调用,但是它不会花费任何东西来使对象容忍多次处理,并且它有助于在某些抛出异常的情况下避免ickiness。
答案 3 :(得分:-1)
如果处理了一个对象,则不应再次处理它。这有助于您不延长垃圾收集器中对象的使用寿命。
我通常使用的模式就是这个。
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class BaseClass: IDisposable
{
/// <summary>
/// A value indicating whether this instance of the given entity has
/// been disposed.
/// </summary>
/// <value>
/// <see langword="true"/> if this instance has been disposed; otherwise,
/// <see langword="false"/>.
/// </value>
/// <remarks>
/// If the entity is disposed, it must not be disposed a second
/// time. The isDisposed field is set the first time the entity
/// is disposed. If the isDisposed field is true, then the Dispose()
/// method will not dispose again. This help not to prolong the entity's
/// life in the Garbage Collector.
/// </remarks>
private bool isDisposed;
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
public void Dispose()
{
this.Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">If true, the object gets disposed.</param>
protected virtual void Dispose(bool disposing)
{
if (this.isDisposed)
{
return;
}
if (disposing)
{
// Dispose of any managed resources here.
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// Note disposing is done.
this.isDisposed = true;
}
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~BaseClass()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}