CustomException
class. The class might look something like this:public class CustomException : System.Exception
{
// Default constructor
public CustomException() : base()
{
}
// Argument constructor
public CustomException(String message) : base(message)
{
}
// Argument constructor with inner exception
public CustomException(String message, Exception innerException) :
base(message, innerException)
{
}
// Argument constructor with serialization support
protected CustomException(
SerializationInfo info, StreamingContext context) :
base(info, context)
{
}
}
You can use this basic setup for any custom exception that you want to create. There is no special code (unless you want to add it) because the base()
entries mean that the code relies on the code found in System.Exception
. What you’re seeing here is the work of inheritance. In other words, for now, you don’t have to worry too much about how this custom exception works. Now consider the catch
clause used here:
public void SomeMethod()
{
try
{
SomeOtherMethod();
}
catch(CustomException ce)
{
}
}
What if SomeOtherMethod()
had thrown a simple Exception or another non-CustomException
type of exception
? It would be like trying to catch a football with a baseball glove — the catch doesn’t match the throw.
Fortunately, C# enables the program to define numerous catch
clauses, each designed for a different type of exception. Assuming that this is the right place to handle the other exceptions, you can tack on one after another. You must line up the multiple catch
clauses for different exception types nose to tail after the try
block. C# checks each catch
block sequentially, comparing the object thrown with the catch
clause’s argument type, as shown in this chunk of code:
public void SomeMethod()
{
try
{
SomeOtherMethod();
}
catch(CustomException ce) // Most specific exception type
{
// All CustomException objects are caught here.
} // You could insert other exception types between these two.
catch(Exception e) // Most general exception type
{
// All otherwise uncaught exceptions are caught here.
// Not that you should always do so -- but when it makes sense ...
}
}
Were SomeOtherMethod()
to throw an Exception
object, it would pass over the catch(CustomException)
because an Exception
isn’t a type of CustomException
. It would be caught by the next catch
clause: the catch(Exception)
.
Always line up the catch
clauses from most specific to most general. Never place the more general catch
clause first, as in this fairly awful bit of code:
public void SomeMethod()
{
try
{
SomeOtherMethod();
}
catch(Exception e) // Most general first -- not good!
{
// All exceptions are caught here.
// The dingo ate everything.
}
catch(CustomException ce)
{
// No exception ever gets this far, because it's
// caught and consumed by the more general catch clause.
}
}
The more general catch
clause starves the catch
clause that follows by intercepting any throw
. The compiler alerts you to this error.
Any class that inherits CustomException IS_A CustomException:
class MySpecialException : CustomException
{
// . . . whatever .. .
}
Given the chance, a CustomException
catch
grabs a MySpecialException
object like a frog nabs flies.