Reputation: 153
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?
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
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
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
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
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
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
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