According to MSDN and this accepted answer,
using (T resource = expression)
embedded-statement
is translated by the compiler as the following code:
{
T resource = expression;//Shouldn't this statement be moved inside the try block?
try
{
embedded-statement
}
finally
{
if (resource != null)
((IDisposable)resource).Dispose();
}
}
My question is: Why is there an extra {}
around the try block? Shouldn't the first statement be moved inside the try block?
MSDN explains:
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):
But according to another MSDN page,
By using a finally block, you can clean up any resources that are allocated in a try block
Updated: If variable visibility is the reason, then how about we declare the variable first and assign it null, then initialize it inside the try block? Is this better than the original code?
{
T resource = null;//Now it is visible in the try block
try
{
resource =expression;// in case an exception is thrown here
embedded-statement
}
finally
{
if (resource != null)
((IDisposable)resource).Dispose();
}
}
CodePudding user response:
Why is there an extra
{}
around the try block?
Because the using
statement is not equivalent to:
T resource = expression;
try
{
embedded-statement
}
finally
{
if (resource != null)
((IDisposable)resource).Dispose();
}
// resource is still in scope here!
resource
is still in scope after the above code, but it should not be in scope after the using
statement.
Imagine if resource
is also the name of a field, and you have put Console.WriteLine(resource);
after the using
statement. Normally, it would have printed the field, but if the using
statement were replaced by the code above, then you would have printed the resource you just allocated instead!
Therefore, to ensure that the semantics remain the same, the extra {}
is needed.
Shouldn't the first statement be moved inside the try block?
No. The using
statement is designed to throw an exception if the initialisation of the resource fails.
By using a finally block, you can clean up any resources that are allocated in a try block
Yes, but that does not mean you have to put every resource in a try
block, nor does that mean putting resources in a try
block is the only way to clean them up.
If the initialisation of resource
throws an exception, the resource will not be initialised, so there is no resource to be disposed of anyway - the finally
block does not need to run in this case, so it is totally fine to put that line outside of the try
.
CodePudding user response:
If the resource was declared in the try-block, it would not be visible in the finally block, because the scope of a variable is always limited to the actual block (and blocks nested more deeply).
The surrounding block limits the scope of the resource to this try-finally construction declaration.
I assume that the "equivalent" try-finally example in the docs is not 100 % equivalent to the using-statement, as it also says:
The try block opens where the variable is declared.
So, I assume that they wrote it before the try-block because of the scope issue, but that it actually would throw inside the try block.
The documentation for try-finally (C# Reference) says:
By using a finally block, you can clean up any resources that are allocated in a try block, and you can run code even if an exception occurs in the try block. Typically, the statements of a finally block run when control leaves a try statement. The transfer of control can occur as a result of normal execution, of execution of a break, continue, goto, or return statement, or of propagation of an exception out of the try statement.