This is probably an obvious tip to most seasoned C# developers, but I often come across people posting code that doesn't handle cleanup properly in the event of an error. (or not at all!)
Any object that implements IDisposable can be wrapped with a using statement as follows:
using(IDisposable x = ...)
{
}
The using statement guarantees that the object will be disposed, even if something goes wrong or if the scope is otherwise exited.
A sample mistake is something like this (simplified for demonstration, this is NOT good code!)
public string ReadHtml(string url) {
System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)WebRequest.Create(url);
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)wr.GetResponse();
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
return sr.ReadToEnd();
}
Now, because this is such a simple demo, you and I can see that the return statement happens before the stream is closed, but when conditional logic is used, this can be much less obvious.
If, instead, this code was written as
public string ReadHtml(string url) {
System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)WebRequest.Create(url);
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)wr.GetResponse();
using(System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream())) {
return sr.ReadToEnd();
}
}
then the stream would be properly disposed.
It's an easy syntax to use and can avoid performance problems when your code goes into production.
Note:
using(...) {} is functionally equivalent to
IDisposable x = ...;
try {
} finally { x.Dispose(); }