using
is syntactic sugar that allows you to guarantee that a resource is cleaned up without needing an explicit try-finally
block. This means your code will be much cleaner, and you won't leak non-managed resources.
Standard Dispose
cleanup pattern, for objects that implement the IDisposable
interface (which the FileStream
's base class Stream
does in .NET):
int Foo()
{
var fileName = "file.txt";
{
FileStream disposable = null;
try
{
disposable = File.Open(fileName, FileMode.Open);
return disposable.ReadByte();
}
finally
{
// finally blocks are always run
if (disposable != null) disposable.Dispose();
}
}
}
using
simplifies your syntax by hiding the explicit try-finally
:
int Foo()
{
var fileName = "file.txt";
using (var disposable = File.Open(fileName, FileMode.Open))
{
return disposable.ReadByte();
}
// disposable.Dispose is called even if we return earlier
}
Just like finally
blocks always execute regardless of errors or returns, using
always calls Dispose()
, even in the event of an error:
int Foo()
{
var fileName = "file.txt";
using (var disposable = File.Open(fileName, FileMode.Open))
{
throw new InvalidOperationException();
}
// disposable.Dispose is called even if we throw an exception earlier
}
Note:
Since Dispose
is guaranteed to be called irrespective of the code flow, it's a good idea to make sure that Dispose
never throws an exception when you implement IDisposable
. Otherwise an actual exception would get overridden by the new exception resulting in a debugging nightmare.
using ( var disposable = new DisposableItem() )
{
return disposable.SomeProperty;
}
Because of the semantics of try..finally
to which the using
block translates, the return
statement works as expected - the return value is evaluated before finally
block is executed and the value disposed. The order of evaluation is as follows:
try
bodyHowever, you may not return the variable disposable
itself, as it would contain invalid, disposed reference - see related example.