Exceptions

Exceptions are functionally identical to the counterpart found in C++ and Java. These are mechanisms we use to be triggered at some condition — usually something bad. The Thanos of exceptions from Java would be NullPointerException, triggered whenever a piece of code attempts to refer to a null pointer, or use a reference type variable that's null. There are a few standard issue exceptions, including IndexOutOfRangeException (for when you use a subscript value for a container than is < 0 or >= the capacity of the container), or DivideByZeroException (for when your program upsets mathematicians).

If your program doesn't implement a way to handle exceptions, there's a good chance it will crash "without grace". Such as would be the case if the program just crashed with nothing more than a pop-up window stating that the "application has stopped working." This type of program crash is just embarrassing, as compared to crashing "with grace", where your application first presents some kind of diagnosis of what went wrong, and perhpas the option to save the error log that can then be sent to the developer. While less than ideal, this at least represents the developers' foresight and compentency to detect and compensate for something going wrong, as opposed to the application performing seppuku.

The Exception class resides within the System namespace that we will probably be using anyway. It is what we call Serializable, which means it can be written out to a data stream and easily reconstructed — a useful feature to include with the aforementioned error logs your program might generate. Exceptions have a ToString() method that we'll use to dump out not just the exception type, but also a brief explanation of what triggered the exception, which method call triggered it, and the parent method of where it was triggered.

Let's first look at an example of how we might throw an exception.

public class Slacker
{
public void doSomething()
{
if (you == "Pretty great!") // Which is always true
{
throw new AwesomeException("WARNING: You're too cool for school!");
}
}
}


Throwing an Exception also has the effect of terminating whatever method was currently being called, immediately returning control to the calling method.

public class Slacker
{
public void doSomething()
{
if (you == "Pretty great!") // Which is always true
{
throw new AwesomeException("WARNING: You're too cool for school!");
}
}

public static void Main()
{
try // a "try" block is where you attempt some code that might generate an Exception
{
doSomething();
}
catch (AwesomeException except) // Followed by "catching" a possibly generated Exception
{
System.Console.WriteLine("Caught an AwesomeException: {0}", except);
// While I don't call "ToString()" explicitly, printing it will call it automatically
}
finally // Code we want executed unconditionally, with or without an Exception
{
airGuitar(); // This requires no explanation
}
}
}


You may have multiple catch blocks for each of the types of Exceptions any particular try may generate, but you will only have one finally block. If you do have multiple catch blocks, list the most specific type of Exception first. You may also elect to have an empty { } catch block, if you would rather simply ignore whatever Exception was generated, although this isn't often recommended. What is recommended is to try and limit the amount of code you toss inside of any given try block — you might feel the temptation to simply write all of your code inside a huge try block that attempts to catch every type of Exception under the sun, but this won't help you when it comes to debugging your program later.

Here's a simple example of how we would build a custom Exception:

public class MyNewException : Exception // Deriving from the "Exception" base class
{
public override string ToString()
{
return "This is the new error message, for MyNewException";
}
}