Должен ли IDisposable.Dispose () быть безопасным звонить несколько раз?

Должны ли реализации IDisposable сделать Dispose () безопасным для вызова несколько раз? Или наоборот? Какой подход подходит для большинства classов .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 членов classа, или я должен просто вызвать this.obj.Dispose() не заботясь о том, был ли он ранее вызван.

Вы должны быть в безопасности, чтобы называть его более одного раза, хотя вам, вероятно, следует избегать его, если сможете.

На странице MSDN на IDisposable.Dispose() :

Если метод Dispose объекта вызывается более одного раза, объект должен игнорировать все вызовы после первого. Объект не должен генерировать исключение, если его метод Dispose вызывается несколько раз.

Да, ваши реализации IDisposable.Dispose () должны допускать многократные вызовы. После первого вызова Dispose () все остальные вызовы могут сразу вернуться.

Я бы предпочел первую часть вашего примера кода, чтобы выставлять и обнулять локальные переменные во время вашей работы.

Имейте в виду, что ваш .Dispose () может вызываться несколько раз, даже если вы реализуете Dispose и null шаблоны в вашем коде. Если несколько потребителей имеют ссылку на один и тот же одноразовый объект, то Dispose этого объекта, вероятно, будет вызываться несколько раз, поскольку эти потребители отказываются от ссылок на него.

Объекты должны быть толерантными к тому, что Dispose вызывается более одного раза, поскольку – особенно при наличии исключений – может быть сложно, чтобы код очистки знал наверняка, какие вещи были очищены, а какие нет. Отбрасывание полей IDisposable при их очистке (и толерантность к тем, которые уже имеют значение null) упростит удаление избыточных вызовов Dispose, но на самом деле ничего не стоит, чтобы объекты допускали множественное удаление, и это помогает избегайте неприятностей в некоторых ситуациях сбрасывания исключений.

Если объект размещен, вы не должны избавляться от него во второй раз. Это помогает вам не продлевать жизнь объекта в сборщике мусора.

Обычно я использую шаблон.

 // A base class that implements IDisposable. // By implementing IDisposable, you are announcing that // instances of this type allocate scarce resources. public class BaseClass: IDisposable { ///  /// A value indicating whether this instance of the given entity has /// been disposed. ///  ///  ///  if this instance has been disposed; otherwise, /// . ///  ///  /// 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. ///  private bool isDisposed; ///  /// Disposes the object and frees resources for the Garbage Collector. ///  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); } ///  /// Disposes the object and frees resources for the Garbage Collector. ///  /// If true, the object gets disposed. 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); } } 
  • Правильное использование интерфейса IDisposable
  • Unity 2.0 и обработка IDisposable типов (особенно с PerThreadLifetimeManager)
  • Как примирить IDisposable и IoC?
  • Если вы реализуете IDisposable.Dispose (), чтобы он никогда не выбрасывал?
  • Как я могу удалить свой stream при реализации загрузки файла в ASP.NET?
  • Что делает Process.Dispose () на самом деле?
  • Вопросы об объекте Entity Framework Context Lifetime
  • Должен ли я вызвать Close () или Dispose () для объектов streamа?
  • Давайте будем гением компьютера.