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.