Exceptions handling
Exceptions handling
Subjects:
- Commonly used anomaly-centric terms
-
The role of .NET exception handling
-
The atoms of .NET exception handling
-
The System.Exception base class
-
The simplest possible example for using of exceptions
-
Throwing a generic exception
-
Catching exceptions
-
System-level and application-level exceptions
-
Insert custom exception using Visual Studio
Subjects:
- Commonly used anomaly-centric terms
-
The role of .NET exception handling
-
The atoms of .NET exception handling
-
The System.Exception base class
-
The simplest possible example for using of exceptions
-
Throwing a generic exception
-
Catching exceptions
Commonly used anomaly-centric terms
Commonly used anomaly-centric terms
Bugs: These are, simply put, errors on the part of the programmer. For example, assume you are programming with unmanaged C++. If you fail to delete dynamically allocated memory (resulting in a memory leak), you have a bug.
User errors: Unlike bugs, user errors are typically caused by the individual running your application, rather than by those who created it. For example, an end user who enters a malformed string into a text box could very well generate an error if you fail to handle this faulty input in your code base.
What Are Exceptions?
What Are Exceptions?
An exception is a runtime error in a program that violates a system or application constraint, or a condition that is not expected to occur during normal operation.
Examples are when a program tries to divide a number by zero or tries to write to a read-only file. When these occur, the system catches the error and raises an exception.
If the program has not provided code to handle the exception, the system will halt the program. For example, the following code raises an exception when it attempts to divide by zero:
static void Main() {
int x = 10, y = 0;
x /= y; // Attempt to divide by zero--raises an exception }
Using an Exceptional Error-Reporting Mechanism
Using an Exceptional Error-Reporting Mechanism
Runtime errors occur when the program is running, not at compile time.
The C# exception mechanism is a means for reporting these errors in a way that the calling method can best understand and use to handle the problem. This mechanism has a lot of advantages over the ways that programmers handled errors in the old days. Let‘s revisit yesteryear so that you can see.
C# introduces a completely different mechanism for capturing and handling errors: the
exception. This mechanism is based on the keywords try, catch, throw, and finally. In outline form, it works like this: A method will try to execute a piece of code. If the code detects a problem, it will throw an error indication, which your code can catch, and no matter what happens, it finally executes a special block of code at the end, as shown in this snippet:
public class MyClass {
public void SomeMethod() {
// Set up to catch an error. try
{
// Call a method or do something that could throw an exception. SomeOtherMethod();
Using an Exceptional Error-Reporting Mechanism
Using an Exceptional Error-Reporting Mechanism
catch(Exception e)
{
// Control passes here in the event of an error anywhere // within the try block.
// The Exception object e describes the error in detail. }
finally
{
// Clean up here: close files, release resources, etc. // This block runs even if an exception was caught. }
}
public void SomeOtherMethod() {
// ... error occurs somewhere within this method ... // ... and the exception bubbles up the call chain.
throw new Exception(“Description of error”);
// ... method continues if throw didn’t happen ... }
}
The combination of try, catch, and (possibly) finally is an exception handler. The SomeMethod() method surrounds a section of code in a block labeled with the keyword try. Any method called within that block (or any method that it calls or on up the tree ...) is considered to be within the try block. If you have a try block, you must have either a
Using an Exceptional Error-Reporting Mechanism
Using an Exceptional Error-Reporting Mechanism
int aVariable; // Declare aVariable outside the block.
try {
aVariable = 1;
// Declare aString inside the block.
string aString = aVariable.ToString(); // Use aVariable in // block.
}
// aVariable is visible here; aString is not.
About
try
blocks
About
try
blocks
Think of using the try block as putting the C# runtime on alert. If an exception pops up while executing any code within this block, hang a lantern in the old church tower (one if by land, two if by sea — or, call 911).
Then, if any line of code in the try block throws an exception — or if any method called within that method throws an exception, or any method called by those methods does, and so on — try to catch it.
Potentially, a try block may “cover” a lot of code, including all methods called by its contents. Exceptions can percolate up (sometimes a long way) from the depths of the execution tree.
The try statement allows you to designate blocks of code to be guarded for exceptions and to supply code to handle them if they occur. The try statement consists of three sections, as shown in Figure.
1. The try block contains the code that is being guarded for exceptions.
2. The catch clauses section contains one or more catch clauses. These are blocks of code to handle the exceptions. They are also known as exception handlers.
About
catch
blocks
About
catch
blocks
A try block is usually followed immediately by the keyword catch, which is followed by the catch keyword’s block. Control passes to the catch block in the event of an error anywhere within the try block. The argument to the catch block is an object of class
Exception or, more likely, a subclass of Exception.
If your catch doesn’t need to access any information from the exception object it catches, you can specify only the exception type:
catch(SomeException) // No object specified here (no // “Exception e”)
{
// Do something that doesn’t require access to exception // object.
}
However, a catch block doesn’t have to have arguments: A bare catch catches any exception, equivalent to catch(Exception):
catch {
About
finally
blocks
About
finally
blocks
A finally block, if you supply one, runs regardless of whether the try block throws an
exception. The finally block is called after a successful try or after a catch. You can use finally even if you don’t have a catch. Use the finally block to clean up before moving on so that files aren’t left open. A common use of finally is to clean up after the code in the try block, whether an exception occurs or not. So you often see code that looks like this:
try { ... }
finally {
// Clean up code, such as close a file opened in the try // block.
}
Handling the Exception
Handling the Exception
The previous example showed that attempting to divide by zero causes an exception. You can modify the program to handle that exception by placing the code inside a try block and supplying a simple catch clause. When the exception is raised, it is caught and handled in
the catch block.
The Exception Classes
The Exception Classes
There are many different types of exceptions that can occur in a program. The BCL defines a number of exception classes, each representing a specific type. When one occurs, the CLR does the following:
• It creates an exception object for the type.
• It looks for an appropriate catch clause to handle it.
The Exception Classes
The Exception Classes
An exception object contains read-only properties with information about the exception that caused it. Table shows some of these properties.
The
catch
Clause
The
catch
Clause
The
catch
Clause
The
catch
Clause
The general catch clause can accept any exception but can’t determine the type of exception that caused it. This allows only general processing and cleanup for whatever exception might occur.
The specific catch clause form takes the name of an exception class as a parameter. It matches exceptions of the specified class or exception classes derived from it.
The specific catch clause with object form gives you the most information about the exception. It matches exceptions of the specified class, or exception classes derived from it. It gives you a reference to the exception object created by the CLR by assigning it to the exception variable. You can access the exception variable’s properties within the block of the catch clause to get specific information about the exception raised.
For example, the following code handles exceptions of type
IndexOutOfRangeException. When one occurs, a reference to the actual exception
What happens when an exception is thrown
What happens when an exception is thrown
When an exception occurs, a variation of this sequence of events takes place:
1. An exception is thrown.
Somewhere deep in the bowels of SomeOtherMethod(), an error occurs. Always at the ready, the method reports a runtime error with the throw of an Exception object back to the first block that knows enough to catch and “handle” it. Note that because an exception is a runtime error, not a compile error, it occurs as the program executes. So an error can occur after you release your masterpiece to the public.
2. C# “unwinds the call stack,” looking for a catch block.
What happens when an exception is thrown
What happens when an exception is thrown
Figure 1: Where can a handler be found?
What happens when an exception is thrown
What happens when an exception is thrown
3. If an appropriate catch block is found, it executes.
An appropriate catch block is one that’s looking for the right exception class (or any of its base classes). As the stack unwinds, if a given method doesn’t have enough context — that is, doesn’t know enough — to correct the exceptional condition, it simply doesn’t provide a catch block for that exception. The right catch may be high up the stack.
The exception mechanism beats the old-fashioned error-return mechanism for these reasons:
• When the calling method gets an old-style return value and can’t do anything useful, it must explicitly return the error itself to its caller, and so on. If the method that can handle the problem is far up the call chain, then returning a return that returned a return that ... grows awkward, leading to some ugly design kludge. (Kludge is an engineer’s term for something that works but is lame and ugly. Think “spit and baling wire”.)
• With exceptions, in contrast, the exception automatically climbs the call chain until it runs into an exception handler. You don’t have to keep forwarding the message, which eliminates a lot of kludgy code.
Kludge is a machine, system, or program that has been badly put together, especially a clumsy but temporarily effective solution to a particular fault or problem.
What happens when an exception is thrown
What happens when an exception is thrown
4. If a finally block accompanies the try block, it executes, whether an exception was caught or not. The finally is called before the stack unwinds to the next-higher method in the call chain. All finally blocks anywhere up the call chain also execute.
5. If no catch block is found anywhere, the program crashes. If C# gets to Main() and doesn’t find a catch block there, the user sees an “unhandled exception” message and the program exits. This is a crash. However, you can deal with exceptions not caught elsewhere by using an exception handler in Main().
This exception mechanism is undoubtedly more complex and difficult to handle than using error codes. You have to balance the increased difficulty against these considerations, as shown in Figure 1:
✦ Exceptions provide a more “expressive” model — one that lets you express a wide variety of error-handling strategies.
✦ An exception object carries far more information with it, thus aiding in debugging — far more than error codes ever could.
✦ Exceptions lead to more readable code — and less code.
Throwing Exceptions Yourself
Throwing Exceptions Yourself
If classes in the .NET class library can throw exceptions, so can you. To throw an exception when you detect an error worthy of an exception, use the throw keyword:
throw new ArgumentException(“Don’t argue with me!”);
You have as much right to throw things as anybody. Because the .NET class library has no awareness of your custom BadHairDayException, who will throw it but you?
If one of the .NET predefined exceptions fits your situation, throw it. But if none fits, you can invent your own custom exception class.
.NET has some exception types that you should never throw or catch:
StackOverflowException, OutOfMemoryException,
ExecutionEngineException,
Knowing What Exceptions Are For
Knowing What Exceptions Are For
Software that can’t complete what it set out to do should throw exceptions. If a method is supposed to process all of an array, for example, or read all of a file — and for some reason can’t complete the job — it should throw an appropriate exception.
A method can fail at its task for various reasons: bad input values or unexpected conditions (such as a missing or smaller than expected file), for example. The task is incomplete or can’t even be undertaken. If any of these conditions occurs in your methods, you should throw an exception.
The overall point here is that whoever called the method needs to know that its task wasn’t completed. Throwing an exception is almost always better than using any error-return code.
“Exceptional” Example
“Exceptional” Example
The following FactorialException program demonstrates the key elements of the exception mechanism:
// FactorialException -- Create a factorial program that
// reports illegal Factorial() arguments using an Exception.
using System;
namespace FactorialException {
// MyMathFunctions -- A collection of mathematical functions // we created
public class MyMathFunctions {
// Factorial -- Return the factorial of the provided value.
public static int Factorial(int value) {
// Don’t allow negative numbers.
if (value < 0) {
// Report negative argument.
string s = String.Format(
“Illegal negative argument to Factorial {0}”, value);
throw new ArgumentException(s);
“Exceptional” Example
“Exceptional” Example
// Begin with an “accumulator” of 1.
int factorial = 1;
// Loop from value down to 1, each time multiplying // the previous accumulator value by the result.
do {
factorial *= value; } while(--value > 1);
// Return the accumulated value.
return factorial; }
}
public class Program {
“Exceptional” Example
“Exceptional” Example
// Here’s the exception handler. try
{
// Call factorial in a loop from 6 down to -6.
for (int i = 6; i > -6; i--) {
// Calculate the factorial of the number.
int factorial = MyMathFunctions.Factorial(i);
// Display the result of each pass.
Console.WriteLine(“i = {0}, factorial = {1}”, i, factorial);
“Exceptional” Example
“Exceptional” Example
catch(ArgumentException e)
{
// This is a “last-chance” exception handler -- the buck
// stops at Main(). Probably all you can do here is alert the // user before quitting.
Console.WriteLine(“Fatal error:”);
// When you’re ready to release the program, change this // output to something in plain English, preferably with // guide-lines for what to do about the problem.
Console.WriteLine(e.ToString()); }
// Wait for user to acknowledge.
Console.WriteLine(“Press Enter to terminate...”); Console.Read();
“Exceptional” Example
“Exceptional” Example
This “exceptional” version of Main() wraps almost its entire contents in a try block. The catch block at the end of Main() catches the ArgumentException object and uses its ToString() method to display most of the error information contained within the exception object in a single string.
Planning Your Exception-Handling Strategy
Planning Your Exception-Handling Strategy
It makes sense to have a plan for how your program will deal with errors. Choosing to use exceptions instead of error codes is just one choice to make. This overview — a set of guidelines and some crucial techniques — should get you well oriented.
Some questions to guide your planning
Several questions should be on your mind as you develop your program:
✦ What could go wrong? Ask this question about each bit of code you write.
✦ If it does go wrong, can I fix it? If so, you may be able to recover from the problem, and the program may be able to continue.
✦ Does the problem put user data at risk? If so, you must do everything in your power to keep from losing or damaging that data. Knowingly releasing code that can mangle user data is akin to software malpractice.
Planning Your Exception-Handling Strategy
Planning Your Exception-Handling Strategy
✦ Which exceptions should I handle? Catch any exception that you can recover from somehow. Try hard to find a way to recover. Then, during development and testing, the unhandled exceptions will reach the top of your program. Before you release the program to real users, fix the underlying causes of any exceptions that go unhandled — if you can. But sometimes an exception should require terminating the program prematurely because things are hopelessly fouled up.
✦ What about exceptions that slip through the cracks and elude my handlers? Providing a “last-chance” exception handler to catch strays.
The role of .NET exception handling
The role of .NET exception handling
Prior to .NET, error handling under the Windows operating system was a confused mishmash of techniques. Many programmers rolled their own error-handling logic within the context of a given application. For example, a development team may define a set of numerical constants that represent known error conditions, and make use of them as method return values.
/* A very C-style error trapping mechanism. */ #define E_FILENOTFOUND 1000
int SomeFunction() {
// Assume something happens in this f(x) // that causes the following return value. return E_FILENOTFOUND;
}
void main() {
int retVal = SomeFunction(); if (retVal == E_FILENOTFOUND) printf("Cannot find file..."); }
The atoms of .NET exception handling
The atoms of .NET exception handling
Programming with exception handling involves the use of four interrelated entities:
- a class type that represents the details of the exception;
- a member that throws an instance of the exception class to the caller;
- a block of code on the caller’s side that invokes the exception-prone member; - a block of code on the caller’s side that will process the exception should it occur.
How to find out which methods throw which exceptions
How to find out which methods throw which exceptions
To find out whether calling a particular method in the .NET class libraries, such as String.IndexOf() — or even one of your own methods — can throw an exception, consider these guidelines:
✦ Visual Studio provides immediate help with tooltips. When you hover the mouse pointer over a method name in the Visual Studio editor, a yellow tooltip window lists not only the method’s parameters and return type but also the exceptions it can throw.
✦ If you have used XML comments to comment your own methods, Visual Studio shows the information in those comments in its IntelliSense tooltips just as it does for .NET methods. If you documented the exceptions your method can throw, you see them in a tooltip. Plug in the <exception> line inside your <summary> comment to make it show in the tooltip.
Grabbing Your Last Chance to Catch an Exception
Grabbing Your Last Chance to Catch an Exception
The FactorialException example wraps all of Main(), except for the final console calls, in an outer, “last-chance” exception handler.
If you’re writing an application, always sandwich the contents of Main() in a try block because Main() is the starting point for the program and thus the ending point as well. (If you’re writing a class library intended for reuse, don’t worry about unhandled exceptions — whoever is using your library needs to know about all exceptions.)
Any exception not caught somewhere else percolates up to Main(). This is your last opportunity to grab the error before it ends up back in Windows, where the error message is much harder to interpret and may frustrate the program’s user.
All the serious code in FactorialException’s Main() is inside a try block. The associated catch block catches any exception whatsoever and outputs a message to the console, and the application exits.
Grabbing Your Last Chance to Catch an Exception
Grabbing Your Last Chance to Catch an Exception
Experiment. To see why you need this last-chance handler, deliberately throw an exception in a little program without handling it. You see what the user would see without your efforts to make the landing a bit softer.
During development, you want to see exceptions that occur as you test the code, in their natural habitat — so you want all of the geekspeak. In the version you release, convert the programmerish details to normal English, display the message to the user, including, if possible, what he might do to run successfully next time, and exit stage right. Make this plain-English version of the exception handler one of the last chores you complete before you release your program into the wild.
Exception Class
Exception Class
Exception Class represents errors that occur during application execution.
This class is the base class for all exceptions. When an error occurs, either the system or the currently executing application reports it by throwing an exception containing information about the error. Once thrown, an exception is handled by the application or by the default exception handler.
Exception Type Features
Exception types support the following features:
Human-readable text that describes the error. When an exception occurs, the runtime
makes available a text message to inform the user of the nature of the error and to suggest action to resolve the problem. This text message is held in the Message property of the exception object. During the creation of the exception object, you can pass a text string to the constructor to describe the details of that particular exception. If no error message argument is supplied to the constructor, the default error message is used.
The state of the call stack when the exception was thrown. The StackTrace property
Exception Class
Exception Class
Exception Type Categories
Two categories of exceptions exist under the base class Exception:
The pre-defined common language runtime exception classes derived from
SystemException.
The user-defined application exception classes derived from
ApplicationException.
Constructors
Name Description
Exception() Initializes a new instance of the Exception class. Exception(String) Initializes a new instance of the Exception class
with a specified error message.
Exception(SerializationInfo, StreamingContext)
Initializes a new instance of the Exception class with serialized data.
Exception Class
Exception Class
Properties
Name Description
Data Gets a collection of key/value pairs that provide additional user-defined information about the exception.
HelpLink Gets or sets a link to the help file associated with this exception. HResult Gets or sets HRESULT, a coded numerical value that is assigned to a
specific exception.
InnerException Gets the Exception instance that caused the current exception. Message Gets a message that describes the current exception.
Source Gets or sets the name of the application or the object that causes the error.
StackTrace Gets a string representation of the immediate frames on the call stack.
TargetSite Gets the method that throws the current exception.
Events
Name Description
SerializeObjec tState
Exception Class
Exception Class
Methods
Name Description
Equals(Object) Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
Finalize Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object.)
GetBaseExceptio n
When overridden in a derived class, returns the Exception that is the root cause of one or more subsequent exceptions.
GetHashCode Serves as a hash function for a particular type. (Inherited from Object.)
GetObjectData When overridden in a derived class, sets the SerializationInfo with information about the exception.
GetType Gets the runtime type of the current instance.
MemberwiseClone Creates a shallow copy of the current Object. (Inherited from Object.)
Exception Class
Exception Class
Exception Class Properties
Exception includes a number of properties that help identify the code location, the type, the help file, and the reason for the exception: StackTrace, InnerException, Message, HelpLink, HResult, Source, TargetSite, and Data.
When a causal relationship exists between two or more exceptions, the InnerException property maintains this information. The outer exception is thrown in response to this inner exception. The code that handles the outer exception can use the information from the earlier inner exception to handle the error more appropriately. Supplementary information about the exception can be stored in the Data property.
The error message string passed to the constructor during the creation of the exception object should be localized, and can be supplied from a resource file using the ResourceManager.
Exception Class
Exception Class
Performance Considerations
A significant amount of system resources and execution time are used when you throw or handle an exception. Throw exceptions only to handle truly extraordinary conditions, not to handle predictable events or flow control. For example, your application can reasonably throw an exception if a method argument is invalid because you expect to call your method with valid parameters. An invalid method argument means something extraordinary has occurred. Conversely, do not throw an exception if user input is invalid because you can expect users to occasionally enter invalid data. In such a case, provide a retry mechanism so users can enter valid input.
Throw exceptions only for extraordinary conditions, then catch exceptions in a general purpose exception handler that applies to the majority of your application, not a handler that applies to a specific exception. The rationale for this approach is that most errors can be handled by validation and error handling code in proximity to the error; no exception needs to be thrown or caught. The general purpose exception handler catches truly unexpected exceptions thrown anywhere in the application.
Exception Class
Exception Class
using System;
class ExceptionTestClass
{
public static void Main() {
int x = 0; try
{
int y = 100/x; }
catch (ArithmeticException e) {
Console.WriteLine("Arithmetic Exception Handler: {0}", e.ToString()); }
catch (Exception e) {
Console.WriteLine("Generic Exception Handler: {0}", e.ToString()); }
} }
Exception Class
Exception Class
This code example produces the following results:
ArithmeticException Class
ArithmeticException Class
ArithmeticException Class: the exception that is thrown for errors in an
arithmetic, casting, or conversion operation. Inheritance Hierarchy:
System.Object
System.Exception
System.SystemException
System.ArithmeticException
System.DivideByZeroException System.NotFiniteNumberException System.OverflowException
Syntax:
public class ArithmeticException : SystemException
ArithmeticException is the base class for DivideByZeroException, NotFiniteNumberException, and OverflowException. In general, use one of the derived classes of ArithmeticException to more precisely indicate the exact nature of the error. Throw an ArithmeticException if you are only interested in capturing a general arithmetic error.
The System.Exception base class
The System.Exception base class
All user- and system-defined exceptions ultimately derive from the System.Exception base class, which in turn derives from System.Object.
public class Exception : ISerializable, _Exception {
// Public constructors
public Exception(string message, Exception innerException);
public Exception(string message);
public Exception();
// Methods
public virtual Exception GetBaseException();
public virtual void GetObjectData(SerializationInfo info, StreamingContext context);
// Properties
public virtual IDictionary Data { get; }
public virtual string HelpLink { get; set; }
public System.Exception InnerException { get; }
public virtual string Message { get; }
public virtual string Source { get; set; }
public virtual string StackTrace { get; }
public MethodBase TargetSite { get; } }
As you can see, many of the properties defined by System.Exception are read-only in nature. This is due to the simple fact that derived types will typically supply default values
for each property (for example, the default message of the
The System.Exception base class
The System.Exception base class
Syntax:
public class SystemException : Exception
This class is provided as a means to differentiate between exceptions defined by the system versus exceptions defined by applications.
SystemException does not provide information as to the cause of the Exception.
In most scenarios, instances of this class should not be thrown. In cases where this class is instantiated, a human-readable message describing the error should be passed to the constructor.
SystemException is thrown by the common language runtime when errors occur that are nonfatal and recoverable by user programs. These errors result from failed runtime check (such as an array out-of-bound error), and can occur during the execution of any method. SystemException adds no new functionality to Exception.
Core members of the
System.Exception
type
Core members of the
System.Exception
type
Property Meaning in Life
Data This property retrieves a collection of key/value pairs (represented by an object implementing IDictionary) that provides additional, programmer-defined information about the exception. By default, this collection is empty (e.g., null).
HelpLink This property returns a URL to a help file or website describing the error in full detail.
InnerException This read-only property can be used to obtain information about the previous exception(s) that caused the current exception to occur. The previous exception(s) are recorded by passing them into the constructor of the most current exception.
Message This read-only property returns the textual description of a given error. The error message itself is set as a constructor parameter.
Source This property returns the name of the assembly that threw the exception.
StackTrace This read-only property contains a string that identifies the sequence of calls that triggered the exception. As you might guess, this property is very useful during debugging or if you wish to dump the error to an external error log.
The simplest possible example for using of exceptions
The simplest possible example for using of exceptions
class Car
{
public const int MaxSpeed = 100;
// Internal state data. private int currSpeed;
private string petName;
private bool carIsDead;
private Radio theMusicBox = new Radio();
public Car() {}
public Car(string name, int currSp) {
currSpeed = currSp; petName = name; }
public void CrankTunes(bool state) {
theMusicBox.TurnOn(state); }
public void Accelerate(int delta) {
if (carIsDead)
Console.WriteLine("{0} is out of order...", petName); else
{
currSpeed += delta;
if (currSpeed > MaxSpeed) {
Console.WriteLine("{0} has overheated!", petName); currSpeed = 0;
carIsDead = true; } else
Console.WriteLine("=> CurrSpeed = {0}", currSpeed); }
} }
class Radio
{
public void TurnOn(bool on) {
if (on) Console.WriteLine("Jamming..."); else Console.WriteLine("Quiet time..."); }
}
class TestCarSpeed
{
static void Main(string[] args) {
Console.WriteLine("** Simple Exception Example **");
Console.WriteLine("=> Creating a car and stepping on it!"); Car myCar = new Car("Zippy", 20);
myCar.CrankTunes(true);
for (int i = 0; i < 10; i++) myCar.Accelerate(10); Console.ReadLine();
Throwing a generic exception
Throwing a generic exception
To retrofit this method to throw an exception if the user attempts to speed up the automobile after it has met its maker, you want to create and configure a new instance of the System.Exception class, setting the value of the read-only Message property via the class constructor. When you wish to send the error object back to the caller, make use of the C# throw keyword. Here is the relevant code update to the Accelerate() method:
// This time, throw an exception if the user speeds up beyond MaxSpeed. public void Accelerate(int delta)
{
if (carIsDead)
Console.WriteLine("{0} is out of order...", petName);
else
{
currSpeed += delta;
if (currSpeed >= MaxSpeed) {
carIsDead = true; currSpeed = 0;
// Use the "throw" keyword to raise an exception.
throw new Exception(string.Format("{0} has overheated!", petName)); }
else
Console.WriteLine("=> CurrSpeed = {0}", currSpeed); }
Catching exceptions
Catching exceptions
Because the Accelerate() method now throws an exception, the caller needs to be ready to handle the exception should it occur. When you are invoking a method that may throw an exception, you make use of a try/catch block. Once you have caught the exception object, you are able to invoke the members of the System.Exception type to extract the details of the problem.
// Handle the thrown exception.
static void Main(string[] args) {
Console.WriteLine("***** Simple Exception Example *****"); Console.WriteLine("=> Creating a car and stepping on it!"); Car myCar = new Car("Zippy", 20);
myCar.CrankTunes(true);
// Speed up past the car's max speed to trigger the exception.
try
{
for (int i = 0; i < 10; i++) myCar. Accelerate(10);
}
catch(Exception e) {
Console.WriteLine("\n*** Error! ***");
Console.WriteLine("Method: {0}", e.TargetSite); Console.WriteLine("Message: {0}", e.Message); Console.WriteLine("Source: {0}", e.Source); }
// The error has been handled, processing continues with the next statement.
Console.WriteLine("\n***** Out of exception logic *****"); Console.ReadLine();
System-level exceptions (
System.SystemException
)
System-level exceptions (
System.SystemException
)
The .NET base class libraries define many classes which ultimately derive from
System.Exception. For example, the System namespace defines core error objects
such as ArgumentOutOfRangeException, IndexOutOfRangeException,
StackOverflowException, and so forth. Other namespaces define exceptions that reflect the behavior of that namespace (e.g., System.Drawing.Printing defines printing exceptions, System.IO defines IO-based exceptions, System.Data defines database-centric exceptions, and so forth).
Exceptions that are thrown by the .NET platform are (appropriately) called system exceptions. System exceptions derive directly from a base class named System.SystemException, which in turn derives from System.Exception (which derives from System.Object).
public class SystemException : Exception
{
// Various constructors.
Application-level exceptions (
System.ApplicationException
)
Application-level exceptions (
System.ApplicationException
)
Given that all .NET exceptions are class types, you are free to create your own application-specific exceptions. However, due to the fact that the System.SystemException base class represents exceptions thrown from the CLR, you may naturally assume that you should derive your custom exceptions from the System.Exception type. While you could do so, best practice dictates that you instead derive from the System.ApplicationException type:
public class ApplicationException : Exception
{
// Various constructors.
}
Building custom exceptions
Building custom exceptions
Assume you wish to build a custom exception (named CarIsDeadException) to represent the error of speeding up a doomed automobile. The first step is to derive a new class from System.ApplicationException (by convention, all exception classes end with the “Exception” suffix; in fact, this is a .NET best practice).
public class CarIsDeadException : ApplicationException
{
private string messageDetails;
private DateTime errorTimeStamp;
private string causeOfError;
public DateTime TimeStamp {
get {return errorTimeStamp;} set {errorTimeStamp = value;} }
public string Cause {
get {return causeOfError;} set {causeOfError = value;} }
public CarIsDeadException(){}
public CarIsDeadException(string message, string cause, DateTime time) {
messageDetails = message; causeOfError = cause; errorTimeStamp = time; }
// Override the Exception.Message property. public override string Message
{ get
{
return string.Format("Car Error Message: {0}", messageDetails); }
Building custom exceptions
Building custom exceptions
public void Accelerate(int delta) {
if (carIsDead)
Console.WriteLine("{0} is out of order...", petName); else
{
currSpeed += delta;
if (currSpeed >= MaxSpeed) {
carIsDead = true; currSpeed = 0;
CarIsDeadException ex = new CarIsDeadException (string.Format("{0} has overheated!", petName), "You have a lead foot", DateTime.Now);
ex.HelpLink = "http://www.CarsRUs.com"; throw ex;
} else
Console.WriteLine("=> CurrSpeed = {0}", currSpeed); }
}
static void Main(string[] args) {
Console.WriteLine("***** Fun with Custom Exceptions *****\n"); Car myCar = new Car("Rusty", 90);
try