So a using statement automatically calls the dispose method on the object that is being \"used\", when the using block is exited, right?
But when is this necessary/benef
It is purely syntactic sugar on top of a try-catch-finally block and a call to the Dispose method. It does not even necessarily define a lexical scope since you can hand it an instance variable. Basically, it makes your code cleaner and easier to maintain.
All the answers about deterministic vs. undeterministic and how the using
works under the hood are correct.
But to pick your specific sample, don't forget that almost all System.Drawing (GDI+ wrapper) objects also hold references to unmanaged memory, so that you may run into trouble when using those extensively without disposing them properly (where using
is the easiest way).
It seems very simple to me.
If a class implements IDisposable, then it is almost asking you to please call Dispose on any instance that you create, as soon as you're done with it. This is the pattern I suggest should be used, whenever such an instance is created:
using (var instanceName = new DisposableClass())
{
// Your code here
}
It's simple, it's clean, and it works for everything except for WCF proxy classes, which are broken. For those, see http://www.iserviceoriented.com/blog/post/Indisposable+-+WCF+Gotcha+1.aspx.
Dispose is called when it exits the using statement because it's explicitly called by that construct. The dispose method isn't called explicitly when the variable goes out of scope (exiting method).
The behavior you MAY observe that looks like that is that usually things that implement IDisposable also call the Dispose method in the classes destructor, and the destructor COULD be called soon after the variable goes out of scope, but not guaranteed. The destructor is invoked by the garbage collector.
the "Using" comes into play when a resource needs to be disposed and it implements the IDisposable interface.
I like to use them like this:
static public void AddSampleData(String name)
{
String CreateScript = GetScript(String.Format("SampleData_{0}", name));
using (IDbConnection MyConnection = GetConnection())
{
MyConnection.Open();
IDbCommand MyCommand = MyConnection.CreateCommand();
foreach (String SqlScriptLine in CreateScript.Split(';'))
{
String CleanedString = SqlScriptLine.Replace(";", "").Trim();
if (CleanedString.Length == 0)
continue;
MyCommand.CommandText = CleanedString;
int Result = MyCommand.ExecuteNonQuery();
}
}
}
They work great for cases where you don't want to put error checking code only cleans up and passes the error on down. The alternative method would look like this:
static public void AddSampleData(String name)
{
String CreateScript = GetScript(String.Format("SampleData_{0}", name));
IDbConnection MyConnection = null;
try
{
IDbConnection MyConnection = GetConnection();
MyConnection.Open();
IDbCommand MyCommand = MyConnection.CreateCommand();
foreach (String SqlScriptLine in CreateScript.Split(';'))
{
String CleanedString = SqlScriptLine.Replace(";", "").Trim();
if (CleanedString.Length == 0)
continue;
MyCommand.CommandText = CleanedString;
int Result = MyCommand.ExecuteNonQuery();
}
}
finally
{
if (MyConnection != null
&& MyConnection.State == ConnectionState.Open)
MyConnection.Close();
}
}
And frankly, which method is easier to read? Same thing with forms:
public void ChangeConfig()
{
using (ConfigForm MyForm = new ConfigForm())
{
DialogResult ConfigResult = MyForm.ShowDialog();
if (ConfigResult == DialogResult.OK)
SaveConfig();
}
ConfigForm MyForm = new ConfigForm();
DialogResult ConfigResult = MyForm.ShowDialog();
MyForm.Dispose();
if (ConfigResult == DialogResult.OK)
SaveConfig();
}