.NET provides developers with the keyword using. Most of the newest code samples are fortunately written with the use of this keyword, in order to demonstrate its functionality, but a lot of older code samples still exist. Yet, why is using so important a keyword?
As you already know, .NET languages are managed programming languages, meaning that their binary files are not native like in C or C++. They are in a bytecode format that .NET's Just In Time compiler converts to native code during execution. This technique allows .NET to avoid memory leaks and to dispose unused objects and handles. While the automatic release of memory with .NET's Garbage Collector works most of the time out of the box, there are a lot of cases where the developer should manage the memory release himself. One of the most common examples is the opening of text files for read or write. Garbage collector simply cannot know if you are done with the file, unless you explicitly say so. There also more evil situations, when you use external references to unmanaged (native) libraries inside a managed project. In those cases, the developer is required to release the reserved memory, since Garbage Collector doesn't "live" in the unmanaged environment of the libraries. And the most evil scenario of all, is when using an external managed reference, which is actually a managed wrapper of an unmanaged library! The using keyword allows us to solve all these cases with a simple and unified way. Let's see that in action in two C# examples:
Explicitly dispose a StreamWriter object
We want to open a text file and write a line of text to it. Without using we could write:
StreamWriter sw = new StreamWriter("myTextFile.txt");
sw.WriteLine("Hello world!");
sw.Close();
sw.Dispose();
With using the above code would be:
using (StreamWriter sw = new StreamWriter("myTextFile.txt"))
{
sw.WriteLine("Hello world!");
}
Notice how we avoid the use of Close() and Dispose functions.
Dispose a managed object which wraps an unmanaged library
Here we want to load a Crystal Report Document, fill it with data, and then export it to a PDF file. Without using we could write:
ReportDocument rptDoc = new ReportDocument();
rptDoc.Load("myReportDocument.rpt");
rptDoc.SetDataSource(myDataSet);
rptDoc.ExportToDisk(ExportFormatType.PortableDocFormat, "myExportedReport.pdf");
rptDoc.Close();
rptDoc.Dispose();
With using the above code would be:
using(ReportDocument rptDoc = new ReportDocument())
{
rptDoc.Load("myReportDocument.rpt");
rptDoc.SetDataSource(myDataSet);
rptDoc.ExportToDisk(ExportFormatType.PortableDocFormat, "myExportedReport.pdf");
}
The benefit of using the using keyword here, is that all the unmanaged resources are really getting disposed, while Close() and Dispose() functions fail in some cases! Blame the developer of the wrapper library, because he didn't implement the IDisposable Interface correctly, but fortunately, using manages to beat this in some magical way! So, in this scenario, using MUST be used in order to have a robust code that works in any case.
From the examples above, we can see that using can make us write better code, by lettings us be more careless (we can forget to Dispose() or Close() our objects, but they will still get disposed), more consistent in our writing style (objects "live" inside our using brackets, so we can instantly determine the lifecycle of our object) and more robust!
So don't forget to use using next time!
As you already know, .NET languages are managed programming languages, meaning that their binary files are not native like in C or C++. They are in a bytecode format that .NET's Just In Time compiler converts to native code during execution. This technique allows .NET to avoid memory leaks and to dispose unused objects and handles. While the automatic release of memory with .NET's Garbage Collector works most of the time out of the box, there are a lot of cases where the developer should manage the memory release himself. One of the most common examples is the opening of text files for read or write. Garbage collector simply cannot know if you are done with the file, unless you explicitly say so. There also more evil situations, when you use external references to unmanaged (native) libraries inside a managed project. In those cases, the developer is required to release the reserved memory, since Garbage Collector doesn't "live" in the unmanaged environment of the libraries. And the most evil scenario of all, is when using an external managed reference, which is actually a managed wrapper of an unmanaged library! The using keyword allows us to solve all these cases with a simple and unified way. Let's see that in action in two C# examples:
Explicitly dispose a StreamWriter object
We want to open a text file and write a line of text to it. Without using we could write:
StreamWriter sw = new StreamWriter("myTextFile.txt");
sw.WriteLine("Hello world!");
sw.Close();
sw.Dispose();
With using the above code would be:
using (StreamWriter sw = new StreamWriter("myTextFile.txt"))
{
sw.WriteLine("Hello world!");
}
Notice how we avoid the use of Close() and Dispose functions.
Dispose a managed object which wraps an unmanaged library
Here we want to load a Crystal Report Document, fill it with data, and then export it to a PDF file. Without using we could write:
ReportDocument rptDoc = new ReportDocument();
rptDoc.Load("myReportDocument.rpt");
rptDoc.SetDataSource(myDataSet);
rptDoc.ExportToDisk(ExportFormatType.PortableDocFormat, "myExportedReport.pdf");
rptDoc.Close();
rptDoc.Dispose();
With using the above code would be:
using(ReportDocument rptDoc = new ReportDocument())
{
rptDoc.Load("myReportDocument.rpt");
rptDoc.SetDataSource(myDataSet);
rptDoc.ExportToDisk(ExportFormatType.PortableDocFormat, "myExportedReport.pdf");
}
The benefit of using the using keyword here, is that all the unmanaged resources are really getting disposed, while Close() and Dispose() functions fail in some cases! Blame the developer of the wrapper library, because he didn't implement the IDisposable Interface correctly, but fortunately, using manages to beat this in some magical way! So, in this scenario, using MUST be used in order to have a robust code that works in any case.
From the examples above, we can see that using can make us write better code, by lettings us be more careless (we can forget to Dispose() or Close() our objects, but they will still get disposed), more consistent in our writing style (objects "live" inside our using brackets, so we can instantly determine the lifecycle of our object) and more robust!
So don't forget to use using next time!