Files and Directories
IDisposable
We've seen previously how we can read and write files using the types FileStream, StreamWriter and StreamReader. In our previous examples, we've manually managed the scope of these variables using targetted calls to their constructors and their Close methods.
It is important when handling Stream instances that we correctly release our resources when we are finished with them. If we don't, we risk consuming more memory then what we need to, or unexpected conditions - such as locks when working with files.
C# provides a built-in mechanism for controlling this sort of resource management, the IDisposable interface and the using statement.
using System; using System.IO; public c...
A using statement is not to be confused with a using directive. This is a directive:
using System;
A using directive is used to include types from a namespace in the current scope.
Here is an example of a using statement:
using (var file = new FileStream(@".\movies.txt", FileMode.Open)) { // Body of statement }
The using statement is a special statement syntax that enforces the correct usage of the IDisposable interface:
public interface IDisposable { void Dispose(); }
The IDisposable interface provides a single method Dispose the is designed to free managed resources used by your object. Let's create an example class that demonstrates what this means:
public class MyDisposable : IDisposable { public void Dispose() { Console.WriteLine("Disposed!"); } }
By itself, I would need to manually call Dispose, but if I use this as a using statement:
using (var my = new MyDisposable()) { Console.WriteLine("Before"); }
If I were to run that, I should see this:
Before Disposed!
The reason is that the using statement generates something similar to the following:
MyDisposable my = new MyDisposable(); try { Console.WriteLine("Before"); } finally { if (my != null) { my.Dispose(); } }
It's not actually C# that is generated, it is the intermediate language, MSIL (we'll cover that in future tutorials), but importantly this syntax structure is generated which ensures the Dispose method is called after the body of the usingstatement is executed. By using this statement syntax, we can ensure we are closing our readers and writers when we're finished with them:
using (var reader = new StreamReader(new FileStream(".\movies.txt", FileMode.Open))) { // Read the file here. } // File is closed and reader is closed at this point.
You can nest multiple using statements easily:
using (var file = new FileStream(".\movies.txt", FileMode.Open)) using (var stream = new StreamReader(file)) { }
Which is the equivalent of:
using (var file = new FileStream(".\movies.txt", FileMode.Open)) { using (var stream = new StreamReader(file)) { } }
Because of this defined pattern around the Dispose method it means our code becomes a lot more terse.