According to the CLI standard (Partition IIA, chapter 19) and the MSDN reference page for the System.Reflection.ExceptionHandlingClauseOptions enum, there are four different kinds of exception handler blocks:
- catch clauses: “Catch all objects of the specified type.”
- filter clauses: “Enter handler only if filter succeeds.”
- finally clauses: “Handle all exceptions and normal exit.”
- fault clauses: “Handle all exceptions but not normal exit.”
Given these brief explanations (cited from the CLI Standard, btw.), these should map to C# as follows:
- catch —
catch (FooException) { … } - filter — not available in C# (but in VB.NET as
Catch FooException When booleanExpression) - finally —
finally { … } - fault —
catch { … }
Experiment:
A simple experiment shows that this mapping is not what .NET’s C# compiler really does:
// using System.Linq;
// using System.Reflection;
static bool IsCatchWithoutTypeSpecificationEmittedAsFaultClause()
{
try
{
return MethodBase
.GetCurrentMethod()
.GetMethodBody()
.ExceptionHandlingClauses
.Any(clause => clause.Flags == ExceptionHandlingClauseOptions.Fault);
}
catch // <-- this is what the above code is inspecting
{
throw;
}
}
This method returns false. That is, catch { … } has not been emitted as a fault clause.
A similar experiment shows that in fact, a catch clause was emitted (clause.Flags == ExceptionHandlingClauseOptions.Clause), even though no exception type has been specified.
Questions:
- If
catch { … }really is a catch clause, then how are fault clauses different from catch clauses? - Does the C# compiler ever output fault clauses at all?
It’s that last line where you went wrong. Read the descriptions again.
faultandfinallyare described practically identically. The difference between them is thatfinallyis always entered, whereasfaultis only entered if control leaves thetryvia an exception. Note that this means that acatchblock may have already acted.If you write this in C#:
Then there is no way that the third block will be entered if control leaves the
tryvia aSpecificException. That’s whycatch {}isn’t a mapping forfault.1Since people keep mentioning this in the comments, a) This part of the answer is a quote from the original question and b) yes,
whenclauses have subsequently been added to C#. It was however accurate at the time of asking and isn’t what this answer focusses on answering.