Shadman Mahmood
Shadman Mahmood

Reputation: 153

C# exception handling finally block before catch block

I am quite confused with how exceptions are getting thrown in C#. If an exception occurs, in the try block, 1.it gets thrown to the catch block, 2. If and only if the catch block catches it the finally block will be executed. 3. The finally block gets executed last, provided the catch statement caught it.

However, when I try to run the program below, the output is A,B not BA.Is there something wrong with my understanding? Thank you.

class Program
 {
     public static void Main(string[] args)
     {
         try
         {
             int a = 2;
             int b = 10 / a;
             try
             {
                 if (a == 1)
                     a = a / a - a;
                 if (a == 2)
                 {
                     int[] c = { 1 };
                     c[8] = 9;
                 }
             }
             finally
             {
                 Console.WriteLine("A");
             }
        }
        catch (IndexOutOfRangeException e)
        {
             Console.WriteLine("B");
        }
        Console.ReadLine();
    }
 }

The exception occurs in a==2, and I know the outer catch will catch this exception. However, the finally is being executed first? Any reason as to why this is showing?

edited

From C# docs we know Finally block gets executed whether or not an exception has occured.

However, my finally block never gets executed and in return I am getting a run time error

class Program
{
    public static void Main(string[] args)
    {
        try
        {
            int a = 2;
            int b = 10 / a;
            try
            {
                if (a == 1)
                    a = a / a - a;
                if (a == 2)
                {
                    int[] c = { 1 };
                    c[8] = 9;
                }
            }
            finally
            {
                Console.WriteLine("A");
            }
        }

        finally{
            Console.WriteLine("finally");
        }
        
        Console.ReadLine();
    }
}

Upvotes: 1

Views: 1936

Answers (6)

vivekagarwal277
vivekagarwal277

Reputation: 585

The way your second code runs is as follows: since there was an exception in inner try block- it executed the inner finally and moved out of the block with the exception. Even in the outer try block there was no catch statement, so again it executed finally block. And then naturally gave you an error as the exception was not caught.

Please note that the exception once created remains in the flow. Unless it is caught and handled - it will lead to unexpected results or errors.

Upvotes: 0

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239636

finally executes when control leaves the try block to which it is attached for any reason; not just if there was a catch block at the same level - that would be a fault handler (in CLR terms) which I think we still cannot do in C#.

So it enters the finally that prints A because control is leaving that try block. It's leaving it because of an exception that's being caught in an outer catch block. That doesn't change any timings/orderings however.


Note that there are some oddities that are possible if the exception is entirely uncaught anywhere in your code. Exception handling happens in two phases. In the first phase, it's trying to locate an appropriate catch clause for the exception, and that can include executing guard clauses (when, C#6 and later). During the second phase, it unwinds the stack and executes any finally clauses as the nesting requires, before reaching the correct level at which the catch clause that will handle the exception is defined1.

I believe that in some environments, if the first phase fails to locate an appropriate exception handler (catch clause) at all, the entire managed environment may be torn down. In such circumstances, the finally clauses aren't executed.

All that is required by a standards conforming CLR is described in the MS Partition I.pdf document, found on ECMA C# and Common Language Infrastructure Standards. Section 12.4.2.5 states:

When an exception occurs, the CLI searches the array for the first protected block that

  • Protects a region including the current instruction pointer and

  • Is a catch handler block and

  • Whose filter wishes to handle the exception

If a match is not found in the current method, the calling method is searched, and so on. If no match is found the CLI will dump a stack trace and abort the program.

(My emphasis)


1Illustrated using a variant of Flydog57's example, also C# 7 local functions:

using System;

namespace PlayAreaCSCon
{
    internal class Program
    {
        static void Main(string[] args)
        {
            TestTryCatchFinally();
            Console.WriteLine("Complete");
            Console.ReadLine();
        }

        private static void TestTryCatchFinally()
        {
            try
            {
                Console.WriteLine("Start Outer Try");
                try
                {
                    Console.WriteLine("Start Inner Try");
                    throw new Exception("Exception from inner try");
                }
                finally
                {
                    Console.WriteLine("In Inner Finally");
                }
            }
            catch (Exception ex) when (GuardHelper(ex))
            {
                Console.WriteLine("In outer catch");
            }
            finally
            {
                Console.WriteLine("In outer finally");
            }

            bool GuardHelper(Exception ex)
            {
                Console.WriteLine("In outer guard");
                return true;
            }
        }
    }
}

This prints:

Start Outer Try
Start Inner Try
In outer guard
In Inner Finally
In outer catch
In outer finally
Complete

Illustrating the two-pass nature of the exception handling (that In outer guard is printed before In Inner Finally)

Upvotes: 6

Flydog57
Flydog57

Reputation: 7111

In your first code, the reason that the finally (A) runs before the catch (B) is because when the exception is thrown, you exit the inner block (causing the finally to run) before the outer block's catch comes into play. Consider this code:

private void TestTryCatchFinally()
{
    try
    {
        Debug.WriteLine("Start Outer Try");
        try
        {
            Debug.WriteLine("Start Inner Try");
            throw new Exception("Exception from inner try");
            Debug.WriteLine("End of Inner Try - never reaced");
        }
        //remove this catch block for second test
        catch (Exception)
        {
            Debug.WriteLine("In inner catch");
        }
        //end of code to remove
        finally
        {
            Debug.WriteLine("In Inner Finally");
        }
    }
    catch (Exception)
    {
        Debug.WriteLine("In outer catch");
    }
    finally
    {
        Debug.WriteLine("In outer finally");
    }
}

If I run this code, I get this output:

Start Outer Try
Start Inner Try
Exception thrown: 'System.Exception' in MyTestApp.exe
In inner catch
In Inner Finally
In outer finally

Which is what you expect. But, if I remove the inner catch block (as noted in the code), I get this output:

Start Outer Try
Start Inner Try
Exception thrown: 'System.Exception' in MyTestApp.exe
In Inner Finally
In outer catch
In outer finally

In this case, as soon as execution exits the inner try block, the finally code executes. Then the outer catch block has it's turn.

Upvotes: 1

Andrew Greatorex
Andrew Greatorex

Reputation: 117

I may be missing something. Don't you want the following?

try
{          
}
catch (Exception ex)
{
}
finally
{  
}

By using a finally{} block, you can ensure that some statements will always run

Upvotes: -1

Svenmarim
Svenmarim

Reputation: 3725

It should look something like this (depents on what you are actually trying to do)

class Program
{
 public static void Main(string[] args)
 {
     try
     {
         int a = 2;
         int b = 10 / a;

        if (a == 1)
            a = a / a - a;
        if (a == 2)
        {
            int[] c = { 1 };
            c[8] = 9;
        }
    }
    catch (IndexOutOfRangeException e)
    {
         //Do something when something in try block throws error
         Console.WriteLine("B");
    }
    finally
    {
        //This code will ALWAYS execute
        //Even when there is no error, A will be written to console
        Console.WriteLine("A");
    }
    Console.ReadLine();
}
}

Upvotes: 0

Jonas Høgh
Jonas Høgh

Reputation: 10874

If you have a single try-catch-finally block, it's true that catch precedes finally. But here, the try-finally and try-catch blocks are being run in order of innermost to outermost. Therefore the finally runs first.

Upvotes: 0

Related Questions