You require a way to always have the
Dispose
method of an object called when that
object’s work is done or it goes out of scope.
using System; using System.IO; // ... using(FileStream FS = new FileStream("Test.txt", FileMode.Create)) { FS.WriteByte((byte)1); FS.WriteByte((byte)2); FS.WriteByte((byte)3); using(StreamWriter SW = new StreamWriter(FS)) { SW.WriteLine("some text."); } }
The using
statement is very easy to use and saves
you the hassle of writing extra code. If the solution had not used
the using
statement, it would look like this:
FileStream FS = new FileStream("Test.txt", FileMode.Create); try { FS.WriteByte((byte)1); FS.WriteByte((byte)2); FS.WriteByte((byte)3); StreamWriter SW = new StreamWriter(FS); try { SW.WriteLine("some text."); } finally { if (SW != null) { ((IDisposable)SW).Dispose( ); } } } finally { if (FS != null) { ((IDisposable)FS).Dispose( ); } }
There are several points about the using
statement.
There is a using
directive, such as
using System.IO;
which should be differentiated from the using
statement. This is potentially confusing to developers first getting
into this language.
The variable(s) defined in the using
statement
clause must all be of the same type, and they must have an
initializer. However, you are allowed multiple
using
statements in front of a single code block,
so this isn’t a significant restriction.
Any variables defined in the using
clause are
considered read-only in the body of the using
statement. This prevents a developer from inadvertently switching the
variable to refer to a different object and causing problems when an
attempt is made to dispose of the object that the variable initially
referenced.
The variable should not be declared outside of the
using
block and then initialized inside of the
using
clause.
This last point is described by the following code:
FileStream FS; using(FS = new FileStream("Test.txt", FileMode.Create)) { FS.WriteByte((byte)1); FS.WriteByte((byte)2); FS.WriteByte((byte)3); using(StreamWriter SW = new StreamWriter(FS)) { SW.WriteLine("some text."); } }
For this example code, we will not have a problem. But consider that
the variable FS
is usable outside of the
using
block. Essentially, we could revisit this
code and modify it as follows:
FileStream FS; using(FS = new FileStream("Test.txt", FileMode.Create)) { FS.WriteByte((byte)1); FS.WriteByte((byte)2); FS.WriteByte((byte)3); using(StreamWriter SW = new StreamWriter(FS)) { SW.WriteLine("some text."); } } FS.WriteByte((byte)4);
This code compiles but throws an
ObjectDisposedException
on the last line of this code snippet
because the Dispose
method has already been called
on the FS
object. The object has not yet been
collected at this point and still remains in memory in the disposed
state.
See Recipe 3.30 and Recipe 3.36; see the “IDispose Interface,” “Using foreach with Collections,” and “Implementing Finalize and Dispose to Clean Up Unmanaged Resources” topics in the MSDN documentation.