C# Exception

Array Collections File Keyword String .NET Cast Class Compression Data Directive Enum Exception If Interface Lambda LINQ Loop Method Number Process Property Regex Sort StringBuilder Struct Switch Time Windows WPF

Exception

Nothing is safe. In programs an error can occur at almost any statement, for almost any reason. Checking for all these errors becomes unbearably complex. Exception handling separates this logic. It simplifies control flow.

Example

In programs we can throw exceptions with a throw statement. But an exception can also be thrown automatically by the runtime. This usually occurs because of the values of variables in your code.

Here:In this program we divide by zero. Sadly this results in a DivideByZeroException.

Try:We use the try and catch blocks to structure our error handling. This may lead to cleaner code.

Based on:

.NET 4.5

Program that throws an exception: C#

using System;

class Program
{
    static void Main()
    {
	try
	{
	    int value = 1 / int.Parse("0");
	    Console.WriteLine(value);
	}
	catch (Exception ex)
	{
	    Console.WriteLine(ex.Message);
	}
    }
}

Output

Attempted to divide by zero.

Properties

Property

We next use the Exception type's properties.
These properties include HelpLink,
Message,
Source,
StackTrace
and TargetSite. This program creates an exception by dividing by zero. Then it catches and displays the exception.

Program that shows exception properties: C#

using System;

class Program
{
    static void Main()
    {
	try
	{
	    int value = 1 / int.Parse("0");
	}
	catch (Exception ex)
	{
	    Console.WriteLine("HelpLink = {0}", ex.HelpLink);
	    Console.WriteLine("Message = {0}", ex.Message);
	    Console.WriteLine("Source = {0}", ex.Source);
	    Console.WriteLine("StackTrace = {0}", ex.StackTrace);
	    Console.WriteLine("TargetSite = {0}", ex.TargetSite);
	}
    }
}

Output
    (StackTrace was abbreviated for display.)

HelpLink =
Message = Attempted to divide by zero.
Source = ConsoleApplication1
StackTrace =    at Program.Main() in C:\...\Program.cs:line 9
TargetSite = Void Main()
Squares

HelpLink:This is empty because it was not defined on the exception. HelpLink is a string property.

Message:This is a short description of the exception's cause. Message is a read-only string property.

Source:This is the application name. Source is a string property that can be assigned to or read from.

StackTrace:This is the path through the compiled program's method hierarchy that the exception was generated from.

TargetSite:This is the name of the method where the error occurred. This property helps simplify what part of the errors are recorded.

Data

Data

It is possible to store structured data on an exception that is thrown in one part of your program, and then later read in this data. Using the Data dictionary on the Exception instance, you can store associative keys and values.

In this example, we use a try construct. In the try block, a new exception is allocated. Next we assign to the Data property. Data can be used as a Hashtable or Dictionary. The keys and values are represented by the object type.

Object
Program that uses Data property: C#

using System;
using System.Collections;

class Program
{
    static void Main()
    {
	try
	{
	    // Create new exception.
	    var ex = new DivideByZeroException("Message");
	    // Set the data dictionary.
	    ex.Data["Time"] = DateTime.Now;
	    ex.Data["Flag"] = true;
	    // Throw it!
	    throw ex;
	}
	catch (Exception ex)
	{
	    // Display the exception's data dictionary.
	    foreach (DictionaryEntry pair in ex.Data)
	    {
		Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
	    }
	}
    }
}

Output

Time = 6/21/2010 11:17:41 AM
Flag = True
Note

Next, the exception instance is thrown. And in the catch block we display the Data contents. The usefulness of the Data property depends on the complexity of your program. In simple programs it won't be useful.

But:In a complex system with many logical dependencies, you can record important information in the Data storage and later use it.

Constructs

Try keyword

We describe the keywords that add exception handling control to your programs. The main topics include how to use throw, catch and finally constructs. These constructs must be used together.

TryCatchFinallyThrowCheck

Checked:The checked and unchecked contexts specify whether exceptions occur when value types overflow.

CheckedUnchecked

Tip:If you use the checked keyword, you can more easily develop a program that correctly avoids all overflow.

Types

Examples

There are many derived exception types in the .NET Framework. Here we look at various exception types. We demonstrate why they are caused. And we try to prevent them from occurring.

ArgumentExceptionArgumentNullExceptionArgumentOutOfRange ExceptionArrayTypeMismatch ExceptionDirectoryNotFoundExceptionDivideByZeroExceptionFileNotFoundExceptionFormatExceptionIndexOutOfRangeExceptionInvalidCastExceptionInvalidOperationExceptionIOExceptionKeyNotFoundExceptionNotImplementedExceptionNullReferenceExceptionOutOfMemoryExceptionOverflowExceptionStackOverflowExceptionTypeInitializationException

Note:There are specific types of database exceptions, including SqlException, SqlCeException and OdbcException.

Custom

Exclamation mark

The .NET Framework includes many built-in exceptions. But this may not be enough. You want even more exceptions. We solve this need with custom exceptions. To make one, create a class and have it derive from Exception.

Tip:You can add a public override string property, Message, to specify the string displayed by the Exception.

Programming tip

Caution:Custom types should be reluctantly used.
They tend to add more complexity.
Consider instead just using built-in ones.

In C#, all exceptions must be represented by an instance of a class type derived from System.Exception. In C++, any value of any type can be used to represent an exception.

The C# Programming Language
Program that throws custom exception: C#

using System;

class TestException : Exception
{
    public override string Message
    {
	get
	{
	    return "This exception means something bad happened";
	}
    }
}

class Program
{
    static void Main()
    {
	try
	{
	    throw new TestException();
	}
	catch (TestException ex)
	{
	    Console.WriteLine(ex);
	}
    }
}

Output

TestException: This exception means something bad happened
   at Program.Main()....

Benchmark

Performance optimization

We test the speed of exception handling. We benchmark a method that uses try-catch against a method that carefully tests for null to avoid failures. Both methods return the first array element if the array is not null.

Program that shows exceptions: C#

using System;

class Program
{
    static void Main()
    {
	int[] arr = new int[] { 1, 2, 3 };

	Console.WriteLine(GetA(arr));
	Console.WriteLine(GetB(arr));

	Console.WriteLine(GetA(null));
	Console.WriteLine(GetB(null));
    }

    /// <summary>
    /// Get the first element, checking for null.
    /// </summary>
    static int GetA(int[] arr)
    {
	if (arr != null)
	{
	    return arr[0];
	}
	else
	{
	    return 0;
	}
    }

    /// <summary>
    /// Get the first element, catching exceptions.
    /// </summary>
    static int GetB(int[] arr)
    {
	try
	{
	    return arr[0];
	}
	catch
	{
	    return 0;
	}
    }
}

Output

1
1
0
0
Cover logo

The error cases never occur in the benchmark. The catch statement is never executed and the parameter is never null. This shows us the cost of null checks versus exceptions that are never thrown.

Result:When an exception is not thrown in the C# code, the try-catch block has a negative effect on performance.

Also:When an exception is actually thrown (which wasn't tested in the benchmark) performance suffers even more.

Data used in benchmark: C#

int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Code tested in tight loops: C#

int v = GetA(arr);
if (v == 5)
{
    i++;
}

int v = GetB(arr);
if (v == 5)
{
    i++;
}

Results
    Iterations: 100000000

GetA - null checks:  95 ms
GetB - uses try:    607 ms

Discussion

Chaos

Even exception constructs that are not executed, and have no effect, cause a performance loss. You can change how your code is structured to improve speed. It is best to use try-catch at the outermost block of loops.

Caution:Optimization should not be ignored. But it sometimes leads to programs that are hard to understand—or even incorrect.

OptimizationFalse literal

Tester-doer. The .NET Framework makes extensive use of the "tester-doer" pattern. This refers to functions that do not throw exceptions on errors. Instead, these functions return an error code (false) and take no action.

Cover logo

Tip:This pattern improves the performance of certain important functions by avoiding exception handling.

Tester-Doer

Further:You can use the tester-doer pattern in your own function designs. It yields similar benefits.

Research

Logic

Exception handling is an extension to structured programming. In the 1960s programs first were divided into reusable units, methods, but this did not consider errors. To contain complexity, exception handling extends methods.

And:It adds another layer of control flow, for errors. We can avoid excess complexity with this new logical layer.

Exceptions in C# provide a structured, uniform, and type-safe way of handling both system-level and application-level error conditions. The C# Programming Language

Summary

The C# programming language

Error checks mess up code readability. Exception handling helps fix this. And programs stop crashing all the time. With Exception types, we describe errors. And with their properties, we access information about errors.

C#