Reputation: 4552
try
{
try
{
throw new Exception("From Try");
}
catch
{
throw new Exception("From Catch");
}
finally
{
throw new Exception("From Finally");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
The above code's output is: From Finally
.
Why it's not From Catch
?
-or-
How can i catch & log from outside both exceptions?
Upvotes: 4
Views: 1215
Reputation: 4592
Because the finally block is always executed.
try
{
try
{
throw new Exception("From Try");
// (1) A new exception object A is created here and thrown.
}
catch // (2) Exception object A is catched.
{
throw new Exception("From Catch");
// (3) A new exception object B is created here and thrown.
}
finally // (4) Execution is forced to continue here!
{
throw new Exception("From Finally");
// (5) A new exception object C is created here and thrown.
}
}
catch (Exception ex) // (6) Exception object C is catched.
{
Console.WriteLine(ex.Message);
}
Every new'd exception object in step (3) and (5) discards the previous one. Since the finally block is always executed all what remains is the exception object C from step (5).
Upvotes: 0
Reputation: 509
Add an extra layer of try-catch blocks like the following:
try {
Exception fromCatch = null;
try {
throw new Exception("From Try");
}
catch {
try {
throw new Exception("From Catch");
}
catch (Exception e) {
// catch failed -> store exception
fromCatch = e;
}
}
finally {
try {
throw new Exception("From Finally");
}
catch (Exception e) {
// i can think of better exception merging... but this shows the idea
throw new Exception(e.Message, fromCatch);
}
// throw fromCatch, in case "From Finally did not happen"
throw fromCatch;
}
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
if (ex.InnerException != null) {
Console.WriteLine(ex.InnerException.Message);
}
}
Reports:
From Finally
From Catch
Edit: this is obviously the answer for question two, as the "why" is answered sufficiently :)
Upvotes: 1
Reputation: 436
This is a very good question, and one that is kind of tricky. Let's go through this step by step:
try
{
throw new Exception("From Try");
}
catch
{
throw new Exception("From Catch");
}
In the code above, Exception("From Try") is thrown and caught by the catch clause (pretty simple so far). The catch clause throws an exception of it's own, which normally we would expect (because the catch is nested in a larger try-catch block) to be caught immediately, but...
finally
{
throw new Exception("From Finally");
}
The finally clause, which is guaranteed to (try to) execute, comes first, and throws an exception of it's own, overwriting the Exception("From Catch") that was thrown earlier.
"A common usage of catch and finally together is to obtain and use resources in a try block, deal with exceptional circumstances in a catch block, and release the resources in the finally block" - MSDN Article
Following this train of logic, we should try our best to refrain from writing code in our catch and finally blocks that is exception-prone. If you're worried about situations like the one you presented cropping up, I'd recommend logging the exceptions and their related information out to an external file, which you can reference for debugging.
Upvotes: 0
Reputation: 273169
Because the finally block executes after the catch block, overriding the exception.
And when an exception happens during the handling of an earlier one, the first one is lost.
How can i catch & log from outside both exceptions?
throw;
or pass the first exception as InnerException of the new one. That is why InnerException
exists.Upvotes: 6
Reputation: 176159
This is the behaviour as it is defined by the C# language specification. Handling of the exception thrown inside the try
block is aborted and instead the exception thrown in the finally
block will be handled.
The relevant section 8.9.5 The throw statement explains how exceptions are propagates:
In the current function member, each
try
statement that encloses the throw point is examined. For each statementS
, starting with the innermosttry
statement and ending with the outermosttry
statement, the following steps are evaluated:
If the try block of
S
encloses the throw point and ifS
has one or morecatch
clauses, thecatch
clauses are examined in order of appearance to locate a suitable handler for the exception. The firstcatch
clause that specifies the exception type or a base type of the exception type is considered a match. A generalcatch
clause (§8.10
) is considered a match for any exception type. If a matchingcatch
clause is located, the exception propagation is completed by transferring control to the block of thatcatch
clause.Otherwise, if the
try
block or acatch
block ofS
encloses the throw point and ifS
has a finally block, control is transferred to the finally block. If thefinally
block throws another exception, processing of the current exception is terminated. Otherwise, when control reaches the end point of thefinally
block, processing of the current exception is continued.
Upvotes: 3
Reputation: 9726
Your code throws a new Exception from each part of the try/catch/finally statement. You are essentially swallowing the previous exception when you create the new error. You can add your "From Try" message to your "From Catch" message with something like
catch(Exception ex)
{
throw new Exception(ex.Message + ":" + "From Catch");
}
I don't know know how you could chain that in the finally though.
Upvotes: 0
Reputation: 77536
finally
happens no matter what. Regardless of whether there was an exception in the try or catch. Thus, you see "From Finally". (This actually is the entire purpose of the finally
clause. So you can put code in there that will clean up resources and the like no matter what -- even if there's an exception.)
Upvotes: 0
Reputation: 50110
finally always runs; and it always runs last. So the lat thing done by the inner try was the finally and that threw something that was caught by the outer catch
not sure if i understand part2 of the question
Upvotes: 0