191
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?

Ganesh Jadhav
  • 2,830
  • 1
  • 20
  • 32
tgandrews
  • 12,349
  • 15
  • 43
  • 55
  • 24
    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 Oct 12 '09 at 16:42
  • 32
    *finally* would be a pretty poor choice of keyword if it didn't run *last*, wouldn't you say? – Eric Lippert Oct 12 '09 at 18:13
  • @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? Thanks – Jeff Puckett Oct 27 '17 at 20:06
  • just naming suggestion use Exception ex - reserve e for events/delegates – mr R Mar 25 '20 at 15:18

8 Answers8

194

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.

Eric Petroelje
  • 59,820
  • 9
  • 127
  • 177
  • 24
    and never if you call Envrionment.FailFast() – Johannes Rudolph Oct 12 '09 at 17:22
  • 27
    After trying the code in Brandon's answer, I see that the `finally` is NOT executed if the exception thrown in the preceding `catch` is never *caught* in an outer `try`-`catch` block! – Andrew Nov 21 '15 at 16:59
  • i remember that the finally got called at all cost, even after returning a value, did they change it? – Hassan Faghihi Sep 13 '17 at 12:10
  • Can you document how you know finally won't get called if exception is never caught? – MBurnham Oct 18 '17 at 20:25
  • 4
    They (Microsoft) talks about it on the new documentation site: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally: "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." – DotNetSparky Jun 16 '18 at 21:27
  • It seems its not as obvious - I tried running this 'DoIt()' method from Marc's answer from a unit test, without any outer try/catches and it **executes** the finally block. Not sure, maybe unit test methods have some kind of implicit catch mechanism? (That was nunit + resharper runner + VS 2017) – Bartosz Feb 05 '19 at 12:29
  • @Bartosz - I believe the unit test runner is set up to catch exceptions inside of your test classes – Eric Petroelje Feb 05 '19 at 16:56
  • 2
    Note that "caught by a try/catch block further up the call stack" will include framework handlers such as those in ASP.NET or a test runner. A better way of putting it might be "if your program continues to run after the catch block, then the finally block will execute." – ArrowCase Oct 21 '19 at 17:40
120

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");
    }
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 6
    +1, for something so simple, you should really just try it like Marc has. GJ illustrating it with nested try/catch/finally :) – Allen Rice Oct 12 '09 at 17:05
  • 3
    @AllenRice why try it if Marc already has, and I can just google to find Marc's answer? Or maybe better, try yourself, then create an SO question and answer it yourself for others' benefit. – joshden Nov 18 '15 at 18:38
  • 11
    Please note that if you don't catch the exception in the outer catch, the inner finally is NEVER executed!! In that case, the output is `outer try` `inner try` `inner catch` `Unhandled Exception: System.DivideByZeroException...` – Andrew Nov 21 '15 at 17:03
  • 1
    @Andrew you are right. The explanation you can find here [MSDN Magazine 2008 September: Unhandled Exception Processing in the CLR](http://download.microsoft.com/download/3/a/7/3a7fa450-1f33-41f7-9e6d-3aa95b5a6aea/MSDNMagazine2008_09en-us.chm) (to open chm it need to unlock: File Properties -> General -> Unlock). If you replace outer catch block with "catch (ArgumentException)" no one finally block won't be proceeded too, because CLR cannot find any "exception handler that agreed to handle the exception" DivideByZeroException. – vladimir Aug 30 '17 at 20:39
50

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

Brandon
  • 1,239
  • 9
  • 17
  • 7
    Great catch, I wasn't aware of that! – Andrew Nov 21 '15 at 16:51
  • 1
    Note that the last finally may run, depending on what you choose: https://stackoverflow.com/a/46267841/480982 – Thomas Weller Sep 18 '17 at 06:23
  • 2
    Interesting... On .NET Core 2.0, the finally part runs after the unhandled exception. – Mahdi Ghiasi Jul 22 '18 at 07:09
  • Interestingly enough, I've just done a test in both .NET Core 2.0 and .NET Framework 4.6.1 and they both run the finally after the unhandled exception. Has this behavior changed? – Cameron Bielstein Aug 07 '18 at 21:31
  • I just ran your test in .Net 5.0 with this result: Example 2: re-throw outside of another try block: --try --catch Unhandled exception. System.Exception: Exception of type 'System.Exception' was thrown. at FinallyTest.Program.Main() in \Program.cs:line 36 --finally The finally block runs on the second test – Gargamel Mar 16 '21 at 07:27
24

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.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
  • I don't not think this is correct. Finally should be inside the outer try block not outside it – Matthew Pigram Feb 06 '14 at 02:41
  • @MatthewPigram: What do you mean? The `finally` block will in fact run after the `catch` block (even if the catch block rethrows the exception), which is what my snippet is trying to illustrate. – Daniel Pryden Feb 06 '14 at 08:07
  • from how I interpret his example he is attempting to do a try catch finally within another try block. NOT a try catch within a try catch finally – Matthew Pigram Feb 06 '14 at 23:07
  • 1
    @MatthewPigram: My answer doesn't have any "try-catch-finally" construct at all. It has a "try-finally", and inside the `try` block of that my answer has a "try-catch". I'm trying to explain the behavior of the 3-part construct by using two 2-part constructs. I don't see any sign of a second `try` block in the original question, so I don't understand where you're getting that. – Daniel Pryden Feb 07 '14 at 07:32
14

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.

  • Unless the thrown exception is caught in another catch somewhere higher up the stack, in which case it may execute if that thrown exception is handled... Or I might be wrong... – tomosius Sep 21 '15 at 23:34
  • @tomosius, yes, that's what Brandon's answer explains. :) – Andrew Nov 21 '15 at 16:52
  • @tomosius That's why I started by specifying "If there is an unhandled exception". If the thrown exception is caught somewhere then by definition we're talking about a different case. – Eusebio Rufian-Zilbermann Jun 13 '17 at 18:36
  • 1
    This is not true. At least not for NET Core 3.1. A simple new console project with this code shows "in the finally" after the exception. – empz Apr 01 '20 at 16:04
  • Interesting that the behavior has changed, .NET core didn't even exist when I posted ;) – Eusebio Rufian-Zilbermann Apr 02 '20 at 20:36
2

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

JonH
  • 32,732
  • 12
  • 87
  • 145
1

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

Van Thi
  • 11
  • 4
1

You can do it, I have done this to ensure cleanup.

using System;
class Program
{
static void Main()
{
    FinallyThrow();
    Console.ReadLine();
}
static void FinallyThrow()
{
    // Get finally block to execute EVEN IF there is an unhandled exception
    Exception thrownEx = null;
    try
    {
        Console.WriteLine("try..");
        throw new InvalidOperationException();
    }
    catch (Exception ex)
    {
        Console.WriteLine("catch..");
        thrownEx = ex;
    }
    finally
    {
        Console.WriteLine("finally..");
        if (thrownEx != null) throw thrownEx;
    }
}
}

OUTPUT (after breaking to the unhandled exception)

try..
catch..
finally..

.Finally always run even if unhandled exception

Paul
  • 94
  • 1
  • 2
  • 1
    You will get a new Stack Trace though; Rather throw a new Exception with thrownEx as the InnerException to preserve the inner Stack Trace – Spoc Oct 31 '22 at 19:55