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. Just as the scope of a resource declared in the using statement is limited to this using statement.
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.
But let's make a test to see what happens. With this class
class Resource : IDisposable
{
public void Dispose()
{
Console.WriteLine("disposing");
}
public override string ToString() => "not null";
}
and this method:
private static Resource Throw()
{
throw new NotImplementedException();
}
let's write this test:
Resource resource = new();
try {
using (resource = Throw()) {
Console.WriteLine("inside using block");
}
Console.WriteLine("after using block");
} catch {
Console.WriteLine($"catch: resource is {resource}");
}
The idea is that we assign a resource before the using statement and throw an exception in the declaration section of the using statement. If the hidden finally-part of the using statement was executed, then disposing
should be printed. But instead, this is printed to the console:
catch: resource is not null
This shows that the using
-statement does in fact not execute the finally
-block, if an exception is thrown in the declaration section.
If a constructor throws an exception, then there is nothing to be disposed anyway.
A factory method should dispose any resources already allocated if an exception is thrown before returning, as this is not the caller's responsibility. The method can then either return null
or throw an exception.
If things are done right, then it does not matter whether a resource is created before or inside the try
part of a try-finally
-statement, since there will be nothing to be disposed if exception should occur.
A try-finally-statement is often used when nothing has to be disposed (because then a using-statement could be used instead) but some state has to be reset. An example is settings the wait-cursor for a long-running operation. Wrapping the long-running operation in a try block and restoring the normal cursor in the finally block ensures that the wait cursor does not persist.