A catch clause specifies what type of exception to catch. This must either be System.Exception or a subclass of System.Exception.
CatchingSystem.Exceptioncatches all possible errors. This is useful when:
Your program can potentially recover regardless of the specific exception type.
You plan to rethrow the exception (perhaps after logging it).
Your error handler is the last resort, prior to termination of the program.
More typically, though, you catch specific exception types, in order to avoid having to deal with circumstances for which your handler wasn’t designed (e.g., anOutOfMemoryException).
You can handle multiple exception types with multiplecatchclauses:
class Test { static void Main (string[] args) { try { byte b = byte.Parse (args[0]); Console.WriteLine (b); } catch (IndexOutOfRangeException ex) { Console.WriteLine ("Please provide at least one argument"); } catch (FormatException ex) { Console.WriteLine ("That's not a number!"); } catch (OverflowException ex) { Console.WriteLine ("You've given me more than a byte!"); } } }
Only onecatchclause executes for a given exception. If you want to include a safety net to catch more general exceptions (such asSystem.Exception), you must put the more specific handlers first.
An exception can be caught without specifying a variable, if you don’t need to access its properties:
catch (StackOverflowException) // no variable { ... }
Furthermore, you can omit both the variable and the type (meaning that all exceptions will be caught):
catch { ... }
In languages other than C#, it is possible (though not recommended) to throw an object that does not derive fromException. The CLR automatically wraps that object in aRuntimeWrapped-Exceptionclass (which does derive fromException).
A finally block always executes—whether or not an exception is thrown and whether or not the try block runs to completion. finallyblocks are typically used for cleanup code.
Afinally block executes either:
After acatchblock finishes
After control leaves thetryblock because of ajumpstatement (e.g.,returnorgoto)
After thetryblock ends
Afinallyblock helps add determinism to a program. In the following example, the file that we open always gets closed, regardless of whether:
Thetryblock finishes normally.
Execution returns early because the file is empty (EndOfStream).
AnIOExceptionis thrown while reading the file.
using System; using System.IO;
class Test { static void Main () { StreamReader reader = null; try { reader = File.OpenText ("file.txt"); if (reader.EndOfStream) return; Console.WriteLine (reader.ReadToEnd ( )); } finally { if (reader != null) reader.Dispose (); } } }
In this example, we closed the file by callingDisposeon theStreamReader. CallingDisposeon an object, within afinallyblock, is a standard convention throughout the .NET Framework and is supported explicitly in C# through theusingstatement.
The using statement
Many classes encapsulate unmanaged resources, such as file handles, graphics handles, or database connections. These classes implement System.IDisposable, which defines a single parameterless method named Dispose to clean up these resources. The usingstatement provides an elegant syntax for instantiating anIDisposableobject and then calling itsDisposemethod within afinallyblock.
The following:
using (StreamReader reader = File.OpenText ("file.txt")) { ... }
Rethrowing in this manner lets you log an error without swallowing it. It also lets you back out of handling an exception should circumstances turn out to be outside what you expected:
string s; using (WebClient wc = new WebClient()) try { s = wc.DownloadString ("http://albahari.com/"); } catch (WebException ex) { if (ex.Status == WebExceptionStatus.NameResolutionFailure) Console.WriteLine ("Bad domain name"); else throw; // Can't handle other sorts of WebException, so rethrow }
The other common scenario is to rethrow a more specific exception type. For example:
try { ... // parse a date of birth from XML element data } catch (FormatException ex) { throw new XmlException ("Invalid date of birth", ex); }
Rethrowing an exception does not affect theStackTraceproperty of the exception (see the next section). When rethrowing a different exception, you can set theInnerExceptionproperty with the original exception if doing so could aid debugging. Nearly all types of exceptions provide a constructor for this purpose.
The most important properties of System.Exception are the following:
StackTrace A string representing all the methods that are called from the origin of the exception to thecatchblock.
Message A string with a description of the error.
InnerException The inner exception (if any) that caused the outer exception. This, itself, may have another InnerException.
All exceptions in C# are runtime exceptions—there is no equivalent to Java’s compile-time checked exceptions.
Common Exception Types
The following exception types are used widely throughout the CLR and .NET Framework. You can throw these yourself or use them as base classes for deriving custom exception types.
System.ArgumentException
Thrown when a function is called with a bogus argument. This generally indicates a program bug.
System.ArgumentNullException
Subclass ofArgumentExceptionthat’s thrown when a function argument is (unexpectedly)null.
System.ArgumentOutOfRangeException
Subclass ofArgumentExceptionthat’s thrown when a (usually numeric) argument is too big or too small. For example, this is thrown when passing a negative number into a function that accepts only positive values.
System.InvalidOperationException
Thrown when the state of an object is unsuitable for a method to successfully execute, regardless of any particular argument values. Examples include reading an unopened file or getting the next element from an enumerator where the underlying list has been modified partway through the iteration.
System.NotSupportedException
Thrown to indicate that a particular functionality is not supported. A good example is calling theAddmethod on a collection for whichIsReadOnlyreturnstrue.
System.NotImplementedException
Thrown to indicate that a function has not yet been implemented.
System.ObjectDisposedException
Thrown when the object upon which the function is called has been disposed.
Please check back next week for the continuation of this series.