Preliminary note:
This question is not intended to bash on .NET, nor is intended to wage a discussing war if there is such a thing as a "Fatal Exception" - Java's designers clearly thought there are, .NET designers either thought otherwise, didn't know otherwise, or there may be another (technical) reason for the exception hierarchy being the way it is.
I'm mostly interested in whether there's a design document or statement by any of the MS designers why the .NET hierarchy is the way it is today. Wild guesses and speculation will make bad answers. Cohesive arguments/examples why there is No Such Thing as a (Categorizable) Fatal Exception certainly can make valid answers, although I'm bound to disagree with them.But, as opposed to comments, I promise not to argue with any cohesive answer ;-) Another category of answers could show evidence that Java's Error
type categorization is a bad idea / doesn't work in practise in Java, thereby implicitly showing why .NET didn't need it. :-)
While working my way through to becoming a more experienced C# programmer, I have noticed something that I consider rather strange(*) in the .NET exception hierarchy:
The base class for all thrown types is Exception
(well, basically anyway).
Specifically, many exceptions directly derive from Exception
and the further categorization into SystemException
-> etc. seems rather pointless a bit arbitrary.
As an example, especially strange to me seems that an SEHException
is-a ExternalExpection
is-a SystemException
when it really would seem to be more like a crash-and-burn kind of error.
While not overly experienced in Java, I find the distinction Java makes wrt. the Error
type vs "normal" Exception
to make a lot of sense. Details can certainly be argued, but .NET
/C# not even trying such an approach seems strange.
Eric Lippert of C# fame has a nice piece on categorizing exceptions which I mostly agree with and which makes me wonder even more why .NET does not even try to provide a bucket for "Fatal Exceptions".
By "Fatal Exception" I basically allude to the same concept Mr. Lippert describes:
Fatal exceptions are not your fault, you cannot prevent them, and you cannot sensibly clean up from them. ...
Note: Most importantly, they are likely and specifically also not the fault of the operation you called that raised the exception.
... They almost always happen because the process is deeply diseased and is about to be put out of its misery. Out of memory, thread aborted, and so on. There is absolutely no point in catching these because nothing your puny user code can do will fix the problem. Just let your "finally" blocks run and hope for the best. (Or, if you're really worried, fail fast and do not let the finally blocks run; at this point, they might just make things worse. But that's a topic for another day.)
I will note that it is totally OK for some set of fatal exception to technically be just like any other exception. You should very well be able to catch it at appropriate times - it's just that for 99% of code it not appropriate to handle these at all.
Take Mr. Lipperts examples: Say I call a function to open a file that can raise various exceptions. If I catch any of these, all I want to do is report that opening the file failed with reason X and continue appropriately. However if opening a file raises, say, a ThreadAbortedException, it doesn't make sense to report anything as not the file open operation failed, but some code aborted the current thread and handling that at the same point as the hypothetical FileNotFoundException doesn't make sense in the vast majority of cases.
Commenters seem to think that only the catch site can really judge whether something is "fatal" and no prior categorization is appropriate, however I would strongly suspect that there is a good list of exceptions that 99% of user code never wishes to catch:
Take StackOverflowException
(and I'm sure there's more) which is "just" a regular SystemException that is hardwired to be fatal:
In the .NET Framework 1.0 and 1.1, you could catch a StackOverflowException object (for example, to recover from unbounded recursion). Starting with the .NET Framework 2.0, you can’t catch a StackOverflowException object with a try/catch block, and the corresponding process is terminated by default.
Note that I do not think a fatal exception must terminate the application immediately (on the contrary). All I ask is why the .NET framework doesn't try to represent "fatalness" in the hierarchy of the exceptions, when the designers clearly do consider some exception more fatal than others.
(*) "consider rather strange" actually means that I, personally, at this very point in the time continuum, find the .NET exception hierarchy totally botched.