1

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();
    }
}
8
  • 1
    Finally will be always executed independently you handle exception or not. So you will see A in console always and B if exception is of type IndexOutOfRangeException. Commented Oct 26, 2018 at 14:31
  • 2
    Specification: Once a matching catch clause is found, the system prepares to transfer control to the first statement of the catch clause. Before execution of the catch clause begins, the system first executes, in order, any finally clauses that were associated with try statements more nested that than the one that caught the exception. Commented Oct 26, 2018 at 14:33
  • Your edit relates to the second half of my answer, where no exception handler at all can be located for the exception. Commented Oct 26, 2018 at 14:36
  • 1
    It seems someone is downvoting every answer. It would be helpful to leave a comment to explain the reason Commented Oct 26, 2018 at 14:47
  • 2
    However, my finally block never gets executed and in return I am getting a run time error That is not true. They are executed AND you get unhandled exception error on runtime. See here: Test. You can see A and finally printed out and then an exception. Commented Oct 26, 2018 at 14:47

6 Answers 6

6

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)

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

0

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.

Comments

0

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();
}
}

3 Comments

I am trying to answer an mcq question
@Svenmarim No, you don't.
That is not true! You can use try-catch-finally, try-catch, try-finally variations.
0

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.

Comments

-1

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

1 Comment

I am actually trying to understand an mcq question, that is why the format is messed up in the first place. However "By using a finally{} block, you can ensure that some statements will always run" doesnt work. Kindly refer to my edit section. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.