Strictly speaking, any object that implements IDisposable
and whose scope is limited to that function should be within a using
block. The IDisposable
interface exists to allow classes that deal with unmanaged resources (database connections, file handles, window handles, etc.) to dispose of these resources in a timely, deterministic fashion.
There are, in general, three ways in which an IDisposable
object is used within a class:
- The object is both created and no longer needed within the scope of a single method call. This is quite common, and is when
using
can (and should) be used.
- The object is created by the class (or is passed to the class), and its lifetime extends beyond the scope of a single method call but not beyond the life of the class. For example, your class creates a
Stream
and needs to use it over the lifetime of the object. In this case, your class should implement IDisposable
itself and dispose of the object(s) that you own when your own Dispose
method is called. An example of this would be something like System.IO.StreamWriter
- The object is passed to the class, but the class doesn't "own" it. This means that the
IDisposable
object's usable lifetime is beyond the scope of a single method call, and may be beyond the lifetime of your object. In this case, someone else must be responsible for calling Dispose
.
The first case is the most common that you'll encounter, which is why the using
block exists. It takes care of ensuring that the object will be disposed of, even in the case of an exception.
Some examples:
- Stream classes
- Database connections/commands
- Controls
There's no exhaustive list of classes that implement IDisposable
, as that list would be fairly large and filled with classes that you'll likely never encounter. Think about what the class does; does it open some sort of connection or file that needs to be closed? In general, does it acquire some kind of resource that needs to be released? If so, it probably implements it. At a basic level, if the compiler allows you to enclose it in using
, then it implements IDisposable
.
As to the consequences of not calling Dispose
, don't consider it. Call Dispose. True, the defensive standard is that if your class uses unmanaged resources directly, then you should define a finalizer that will call dispose in the event that your object is collected and someone has failed to call it, but that should not be a design choice. Ever, as far as I'm aware.