163
votes
try {
   // Do stuff
}
catch (Exception e) {
   throw;
}
finally {
   // Clean up
}

In the above block when is the finally block called? Before the throwing of e or is finally called and then catch?

7
p.s. you should not "throw e;" because that will mess up the stack trace of the original exception. You should just "throw;". Or create a new exception and set the InnerException to "e" before you throw it.Erv Walter
finally would be a pretty poor choice of keyword if it didn't run last, wouldn't you say?Eric Lippert
@ErvWalter is this still true? I am testing it both ways in VS2017, and it appears to be exactly the same. Could you provide some more information or a reference? ThanksJeff Puckett
just naming suggestion use Exception ex - reserve e for events/delegatesmr R

7 Answers

164
votes

It would be called after e is re-thrown (i.e. after the catch block is executed)

editing this 7 years later - one important note is that if e is not caught by a try/catch block further up the call stack or handled by a global exception handler, then the finally block may never execute at all.

105
votes

Why not try it:

This is the output from executing the code below:

outer try
inner try
inner catch
inner finally
outer catch
outer finally

with code (formatted for vertical space):

static void Main() {
    try {
        Console.WriteLine("outer try");
        DoIt();
    } catch {
        Console.WriteLine("outer catch");
        // swallow
    } finally {
        Console.WriteLine("outer finally");
    }
}
static void DoIt() {
    try {
        Console.WriteLine("inner try");
        int i = 0;
        Console.WriteLine(12 / i); // oops
    } catch (Exception e) {
        Console.WriteLine("inner catch");
        throw e; // or "throw", or "throw anything"
    } finally {
        Console.WriteLine("inner finally");
    }
}
44
votes

After reading all of the answers here it looks like the final answer is it depends:

  • If you re-throw an exception within the catch block, and that exception is caught inside of another catch block, everything executes according to the documentation.

  • However, if the re-trown exception is unhandled, the finally never executes.

I tested this code sample in VS2010 w/ C# 4.0

static void Main()
    {
        Console.WriteLine("Example 1: re-throw inside of another try block:");

        try
        {
            Console.WriteLine("--outer try");
            try
            {
                Console.WriteLine("----inner try");
                throw new Exception();
            }
            catch
            {
                Console.WriteLine("----inner catch");
                throw;
            }
            finally
            {
                Console.WriteLine("----inner finally");
            }
        }
        catch
        {
            Console.WriteLine("--outer catch");
            // swallow
        }
        finally
        {
            Console.WriteLine("--outer finally");
        }
        Console.WriteLine("Huzzah!");

        Console.WriteLine();
        Console.WriteLine("Example 2: re-throw outside of another try block:");
        try
        {
            Console.WriteLine("--try");
            throw new Exception();
        }
        catch
        {
            Console.WriteLine("--catch");
            throw;
        }
        finally
        {
            Console.WriteLine("--finally");
        }

        Console.ReadLine();
    }

Here is the output:

Example 1: re-throw inside of another try block:
--outer try
----inner try
----inner catch
----inner finally
--outer catch
--outer finally
Huzzah!

Example 2: re-throw outside of another try block:
--try
--catch

Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown.
at ConsoleApplication1.Program.Main() in C:\local source\ConsoleApplication1\Program.cs:line 53

25
votes

Your example would behave identically to this code:

try {
    try {
        // Do stuff
    } catch(Exception e) {
        throw e;
    }
} finally {
    // Clean up
}

As a side note, if you really mean throw e; (that is, throw the same exception you just caught), it is much better to just do throw;, since that will preserve the original stack trace instead of creating a new one.

14
votes

If there is an unhandled exception inside a catch handler block, the finally block gets called exactly zero times

  static void Main(string[] args)
  {
     try
     {
        Console.WriteLine("in the try");
        int d = 0;
        int k = 0 / d;
     }
     catch (Exception e)
     {
        Console.WriteLine("in the catch");
        throw;
     }
     finally
     {
        Console.WriteLine("In the finally");
     }
  }

Output:

C:\users\administrator\documents\TestExceptionNesting\bin\Release>TestExceptionNesting.exe

in the try

in the catch

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero. at TestExceptionNesting.Program.Main(String[] args) in C:\users\administrator\documents\TestExceptionNesting\TestExceptionNesting.cs:line 22

C:\users\administrator\documents\TestExceptionNesting\bin\release>

I got asked this question today at an interview and the interviewer kept going back "are you sure the finally doesn't get called?" I was uncertain if it was meant a trick question or the interviewer had something else in mind and wrote the wrong code for me to debug so I came home and tried it (build and run, no debugger interaction), just to put my mind at rest.

2
votes

A simple way to tell also is to debug your code and notice when finally is called.

1
votes

Testing with a C# Console Application, the finally code has been executed after the exception is thrown: The "Application Error Dialog" existed and after you chose "Close the program" option, the finally block was executed in that console window. But setting the breaking point inside the finally code block, I can never hit it. The debugger keeps stopping at the throw statement. Here is my test code:

    class Program
    {
       static void Main(string[] args)
       {
          string msg;
          Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
       }

       static int GetRandomNumber(out string errorMessage)
       {
         int result = 0;
         try
         {
            errorMessage = "";
            int test = 0;
            result = 3/test;
            return result;
         }
         catch (Exception ex)
         {
            errorMessage = ex.Message;
            throw ex;

         }
         finally
         {
            Console.WriteLine("finally block!");
         }

       }
    }

Debugging in VS2010 - .NET Framework 4.0