So just out of curiosity I wanted to see what was special about the exception class that allowed it to be used with the keyword Throw
while a standard class is not.
All I found is that the Exception class implemented the following
public class Exception : System.Object, System.Runtime.Serialization.ISerializable, System.Runtime.InteropServices._Exception
{
}
So I tried implementing those same interfaces and attempting to throw my own custom exception that did not derive from System.Exception
to no avail. I was simply advised that
The type caught or thrown must be derived from System.Exception
So is there any specific reason for this? I assume there is as few choices in managed languages seem to be arbitrary.
I think your premise is mistaken. It is possible that an object is thrown that is not derived from System.Exception
. You just can't throw it in C# or examine the object in a catch clause. From section 8.10 of the C# spec (v4.0):
Some programming languages may support exceptions that are not
representable as an object derived from System.Exception, although
such exceptions could never be generated by C# code. A general catch
clause may be used to catch such exceptions. Thus, a general catch
clause is semantically different from one that specifies the type
System.Exception, in that the former may also catch exceptions from
other languages.
An example of a general catch:
try
{
}
catch (Exception) { } // 'specific' catch
catch { } // 'general' catch
In particular, this is important when calling unmanaged code.
Some types always seem to get special treatment in every language. Mostly because they are so fundamental to the system. System.Exception
, System.ValueType
, System.Delegate
are all special types in C# that are tightly bound to language keywords and the CLR, so it is not surprising that you can't just implement classes that take over their roles.
Design Guidelines for Exceptions
Exceptions are the standard mechanism for reporting errors.
Applications and libraries should not use return codes to communicate
errors. The use of exceptions adds to a consistent framework design
and allows error reporting from members, such as constructors, that
cannot have a return type
throw (C# Reference)
The thrown exception is an object whose class is derived from
System.Exception, as shown in the following example.
class MyException : System.Exception {}
// ...
throw new MyException();
Exceptions Overview
In the .NET Framework, an exception is an object that inherits from
the Exception Class
So, your exception must derive from System.Exception
, but it's up to you, how you organize it within.
It is an arbitrary choice of the designers of the CLS. Presumably they made this choice for reasons of consistency. C# follows the CLS; the requirement is enforced by the compiler for this reason, not for any technical reason related to the implementation of the Exception type.
The CLI can actually throw any object. See http://jilc.sourceforge.net/ecma_p3_cil.shtml#_Toc524462405.
The language uses System.Exception
as a base for all exceptions. This essentially means that any throwable or catchable exception shouldn't error out if you do (Exception)myExc
. This is probably because the definition of the System.Exception
class is used so that all exceptions adhere to the same interface. Because of the consistent interface, exceptions arrive with a stack trace and a meaningful message (for example), which is invaluable for logging.
One reason why every exception needs to have a universal base class is so you can catch every type of exception in a single catch block.
If I have this:
try
{
...
}
catch(Exception ex)
{
// Handle somehow
}
That will catch ALL exceptions, and will allow me to display what it is (by using ex.Message
).
If you could throw anything, then how would you have a catch that would catch everything and still give you access to the object thrown?
You could have this, which will catch absolutely everything:
try
{
...
}
catch
{
// Handle somehow
}
But you have 'lost' the thing that was thrown.