2 out of 4 rated this helpful - Rate this topic

try-finally (C# Reference)

Updated: August 2011

The finally block is useful for cleaning up any resources that are allocated in the try block, and for running any code that must execute even if an exception occurs in the try block. Typically, the statements of a finally block are executed when control leaves a try statement, whether the transfer of control occurs 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.

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

In the following example, an invalid conversion statement causes a System.InvalidCastException exception. The exception is unhandled.


public class ThrowTestA
{
    static void Main()
    {
        int i = 123;
        string s = "Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // To run the program in Visual Studio, type CTRL+F5. Then 
            // click Cancel in the error dialog.
            Console.WriteLine("\nExecution of the finally block after an unhandled\n" +
                "error depends on how the exception unwind operation is triggered.");
            Console.WriteLine("i = {0}", i);
        }
    }
    // Output:
    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
    //
    // Execution of the finally block after an unhandled
    // error depends on how the exception unwind operation is triggered.
    // i = 123
}


In the following example, an exception from the TryCast method is caught in a method farther up the call stack.


public class ThrowTestB
{
    static void Main()
    {
        try
        {
            // TryCast produces an unhandled exception.
            TryCast();
        }
        catch (Exception ex)
        {
            // Catch the exception that is unhandled in TryCast.
            Console.WriteLine
                ("Catching the {0} exception triggers the finally block.",
                ex.GetType());

            // Restore the original unhandled exception. You might not
            // know what exception to expect, or how to handle it, so pass 
            // it on.
            throw;
        }
    }

    public static void TryCast()
    {
        int i = 123;
        string s = "Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // Report that the finally block is run, and show that the value of
            // i has not been changed.
            Console.WriteLine("\nIn the finally block in TryCast, i = {0}.\n", i);
        }
    }
    // Output:
    // In the finally block in TryCast, i = 123.

    // Catching the System.InvalidCastException exception triggers the finally block.

    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
}


For more information about finally, see try-catch-finally.

C# also contains the using statement, which provides a convenient syntax for the same functionality as a try-finally statement.

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

Date

History

Reason

August 2011

Clarified when the finally block is run. Added an example.

Customer feedback.

May 2010

Added write statements and instructions in the example to clarify the results.

Customer feedback.

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Re: Finally does not always run

It's true that a finally block may not get run, I have verified it. I've just experienced it while working, I came here, and I found Chris's post. I'm tagging it as ContentBug to get some attention from MSFT, although it affects the C# specification much more importantly than the MSDN library. If this behavior were by design, it should be clear in the specification: only now I've noticed that section 16.3 may be interpreted in this light, but unless I'm reading it wrong, section 8.10 asserts that finally blocks are always run even if the try statement has no catch blocks.

My guess is that this is an optimization, since finally blocks are intended above all for cleaning up resources, but those will be freed anyway when the un-handled exception causes the process to be nuked? It doesn't sound right anyway, it looks like undefined behavior, and the purpose of the finally blocks seems beaten. It should be clear in the specification under which circumstances a finally block will not run, because we may use it for code that we need to run, but not necessarily about cleaning up handles and such, and apparently we need a catch block for that, even if we want to re-throw from it.

PS: I think Chris meant section 16.3 of the C# specification, not the CLR one (though I don't have the latter handy).

Edit from SJ at MSFT: Thanks Javier and Chris. I will check this out with the product team.

Edit #2 from SJ at MSFT: I've worked my way up the development chain on this one, and I will revise the topic to reflect what I have learned. The short version is that for unhandled exceptions, such as the current example, execution of the finally block is dependent on whether the exception unwind operation is triggered. For in-depth information, take a look at this article from MSDN Magazine:  http://msdn.microsoft.com/en-us/magazine/cc793966.aspx .

Javier: Thanks a lot SJ for the feedback and the clarification.

Finally does not always run
Finally blocks do not always get run as reliably as this article makes out (http://stackoverflow.com/questions/4193493/finally-block-not-running and section 16.3 of the CLR spec) - if an Exception escapes from your application (IE it gets to your apps entry point and you have not caught it) then you cannot rely on Finally blocks being run at all - and not only is the answer "they might get run it depends on the implementation of the CLR you use" the answer is "they might get run, it depends on implementation, and one implementation (.NET 4.0 on windows 7 in our case) can behave differently in different situations."

If you have critical code in finally blocks, always make sure you have a global error handler that does not throw outside of your app, or they may not get run.