Using' Statement VS 'Try Finally'

using' statement vs 'try finally'

From MSDN, using Statement (C# Reference)

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):

{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}

So basically, it is the same code but with a nice automatic null-checks and an extra scope for your variable. The documentation also states that it "ensures the correct use of IDisposable object" so you might as well gets even better framework support for any obscure cases in the future.

So go with option 2.

Having the variable inside a scope that ends immediately after it's no longer needed is also a plus.

How C# Using Statement Translates to Try-Finally

It really does behave like a try/finally - so if the application terminates, the resource may not be disposed... and that's usually okay, because normally disposal is for releasing resources held by the process... and the OS will tidy those up anyway on process death. (That's not to say the Dispose method won't be called... it's just the same as with a normal try/finally.)

Obviously if you've got a "lock file" on the file system or something like that, that would be a problem - but you'd have the same problem in the face of a power cut etc.

Does a C# using statement perform try/finally?

You are correct; the using statement compiles to a try / finally block.

The compiler transforms using(resource) statement; into the following code:

{
ResourceType resource = expression;
try {
statement;
}
finally {
if (resource != null) ((IDisposable)resource).Dispose();
}
}

(The cast to IDisposable is in case ResourceType implements IDisposable explicitly.

Difference between Try-Finally Dispose and Using-statement

During compilation, the using statement translates to:

try
{
}
finally
{
((IDisposable)connection).Dispose();
}

You can actually define two Dispose() methods inside the same class, one explicitly for the IDisposable interface, and a class method:

public class X : IDisposable
{
void IDisposable.Dispose() { }
public void Dispose() { }
}

You could really ruin someone's day by letting these methods have different behavior, though.

Furthermore, you can create a Dispose() method in a class that does not implement IDisposable, but you won't be able to place it in a using statement.

Using statement and try-catch()-finally repetition?

You can implement the pattern yourself if you need to handle some exceptions if you really want to. Personally, I still find it simpler (and more importantly, clearer) to just wrap the using in try/catch block.

But if you do it yourself, make sure you get it right. The Using block also creates an anonymous scope block so that your variable becomes eligible for collection sooner. The .Dispose() method that's called at the end of the Using block only cleans up unmanaged resources, and so any memory your object holds may hang around a little longer. It's not likely a huge concern, but it is worth remembering just in case.

So, to do a direct adaption of the pattern, your code needs to look more like this:

{
FileStream fs;
try
{
fs = File.Open(path);

}
catch (FileNotFoundException e) { /* ... */ }
catch (IOException e) { /* ... */ }
catch (Exception e) {/* ... */}
finally
{
if (fs != null) fs.Dispose();
}
}

Personally, I'd like to see Using expanded to support Catch and Finally blocks. Since they're already performing a transformation on the code, it doesn't seem like this would add that much additional complexity.

Why would try/finally rather than a using statement help avoid a race condition?

Yeah, there is a possible race in the using statement. The C# compiler transforms

using (var obj = new Foo()) {
// statements
}

to:

var obj = new Foo();
try {
// statements
}
finally {
if (obj != null) obj.Dispose();
}

The race occurs when the thread is aborted right between the obj assignment statement and the try block. Extremely small odds but not zero. The object won't be disposed when that happens. Note how he rewrote that code by moving the assignment inside the try block so this race cannot occur. Nothing actually goes fundamentally wrong when the race occurs, disposing objects is not a requirement.

Having to choose between making thread aborts marginally more efficient and writing using statements by hand, you should first opt for not getting in the habit of using Thread.Abort(). I can't recommend actually doing this, the using statement has additional safety measures to ensure accidents don't happen, it makes sure that the original object gets disposed even when the object is re-assigned inside the using statement. Adding catch clauses is less prone to accidents as well. The using statement exists to reduce the likelihood of bugs, always use it.


Noodling on a bit about this problem, the answer is popular, there's another common C# statement that suffers from the exact same race. It looks like this:

lock (obj) {
// statements
}

Translated to:

Monitor.Enter(obj);
// <=== Eeeek!
try {
// statements
}
finally {
Monitor.Exit(obj);
}

Exact same scenario, the thread abort can strike after the Enter() call and before entering the try block. Which prevents the Exit() call from being made. This is way nastier than a Dispose() call that isn't made of course, this is almost certainly going to cause deadlock. The problem is specific to the x64 jitter, the sordid details are described well in this Joe Duffy blog post.

It is very hard to reliably fix this one, moving the Enter() call inside the try block can't solve the problem. You cannot be sure that the Enter call was made so you cannot reliably call the Exit() method without possibly triggering an exception. The Monitor.ReliableEnter() method that Duffy was talking about did eventually happen. The .NET 4 version of Monitor got a TryEnter() overload that takes a ref bool lockTaken argument. Now you know it is okay to call Exit().

Well, scary stuff that goes BUMP in the night when you are not looking. Writing code that's safely interruptable is hard. You'd be wise to never assume that code that you didn't write got all of this taken care of. Testing such code is extremely difficult since the race is so rare. You can never be sure.

Replace using statement with equal try/finally block

It's rather like this:

MemoryStream ms = null;
try
{
ms = new MemoryStream();

//code
}
finally
{
if (ms != null) ms.Dispose();
}

The reason is that the mere instantiation may create disposable resources.

Using statement with try catch. What happens to instance from using statement?

You can think of using as a short-hand for try-finally. Hence your code is equivalent to:

IDatabaseConnectivityObject databaseConnectivityObject = new DbProviderFactoryConnectionBasicResponse();
try
{
try
{
Foo();
}
catch(ArgumentNullException e)
{
throw;
}
}
finally
{
if(databaseConnectivityObject != null)//this test is often optimised away
databaseConnectivityObject.Dispose()
}

Looked at this way, you can see that the Dispose() will indeed be called if the exception throws, because the try-finally is outside of the try-catch.

This is precisely why we use using.

using statement in C# - Is this a nested try/finally?

Using statements will automatically call Dispose() for any IDisposable object within it declaration. It's important to note that this is not a replacement for any try/catch/finally statements that your own code may need to do. The using statement ensures that Dispose() will be called if any code within it's block throws or not. This is extremely important any time I/O objects are used such as network calls, stream reading, database calls, etc. This will make sure you don't have memory leaks or locked files.

using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
//an exception or not will call Dispose() on selectCommand

using (IDataReader theData = selectCommand.ExecuteReader())
{
//an exception or not will call Dispose() on theData

while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
}

The "equivalent" to running this code without using statements would be:

var selectCommand = this.createCommand(selectSQL);
try
{
var theData = selectCommand.ExecuteReader();
try
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
finally
{
if (theData != null)
{
theData.Dispose();
}
}
}
finally
{
if (selectCommand != null)
{
selectCommand.Dispose();
}
}

However, the above code should not be used since the using statement is refined, optimized, guaranteed, etc, but the gist of it is above.



Related Topics



Leave a reply



Submit