Object Lifetime

  • Use the using statement to precisely delineate the lifetime of IDisposable objects.
  • Use try/finally blocks to manage other state (e.g. executing a matching EndUpdate() for a BeginUpdate())
  • Do not set local variables to null. They will be automatically de-referenced and cleaned up.

IDisposable

  • Implement IDisposable if your object uses disposable objects or system resources.
  • Be careful about making your interfaces IDisposable; that pattern is a leaky abstraction and can be quite invasive.
  • Implement Dispose() so that it can be safely called multiple times (see example below).
  • Don’t hide Dispose() in an explicit implementation. It confuses callers unnecessarily. If there is a more appropriate domain-specific name for Dispose, feel free to make a synonym.

Finalize

  • There are performance penalties for implementing Finalize. Implement it only if you actually have costly external resources.
  • Call the GC.SuppressFinalize method from Dispose to prevent Finalize from being executed if Dispose() has already been called.
  • Finalize should include only calls to Dispose and base.Finalize().
  • Finalize should never be public

Destructors

  • Avoid using destructors because they incur a performance penalty in the garbage collector.
  • Do not access other object references inside the destructor as those objects may already have been garbage-collected (there is no guaranteed order-of-destruction in the IL or .NET runtime).

Best Practices

The following class expects the caller to use a non-standard pattern to avoid holding open a file handle.

  1. public class Weapon
  2. {
  3. public Load(string file)
  4. {
  5. _file = File.OpenRead(file);
  6. }
  7. // Aim(), Fire(), etc.
  8. public EjectShell()
  9. {
  10. _file.Dispose();
  11. }
  12. private File _file;
  13. }

Instead, make Weapon disposable. The following implementation follows the recommended pattern. R# can help you create this pattern.

Note that _file is set to null so that Dispose can be called multiple notes, not to clear the reference.

  1. public class Weapon : IDisposable
  2. {
  3. public Weapon(string file)
  4. {
  5. _file = File.OpenRead(file);
  6. }
  7. // Aim(), Fire(), etc.
  8. public Dispose()
  9. {
  10. Dispose(true);
  11. GC.SuppressFinalize(this);
  12. }
  13. protected virtual void Dispose(bool disposing)
  14. {
  15. if (disposing)
  16. {
  17. if (_file != null)
  18. {
  19. _file.Dispose();
  20. _file = null;
  21. }
  22. }
  23. }
  24. private File _file;
  25. }

Using the standard pattern, R# and Code Analysis will detect when an IDisposable object is not disposed of properly.