Home > Mobile >  C# 'using' statement translated by the compiler into 'try finally'
C# 'using' statement translated by the compiler into 'try finally'

Time:11-30

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.

  •  Tags:  
  • c#
  • Related