try Statements and Exceptions

Try statement specifies a code block subject to error-handling. Try block must be followed by a catch block , finally block or both.

catch block

Executes when an error occurs in the try block, access an Exception object that contains information about the error, however you can use to compensate the error or rethrow the exception.

finally block

Executes after execution leaves the try block and if present the catch block, useful for cleanup tasks such as closing network connections.,/p>

Try statement code block:

try
{
   ... // exception may get thrown within execution of this block
}
catch (ExceptionA ex)
{
   ... // handle exception of type ExceptionA 
}
catch (ExceptionB ex)
{
   ... // handle exception of type ExceptionB 
}
finally
{
   ... // cleanup code
}

DivideByZeroException

// Because Calc is called with x==0, the runtime throws a DivideByZeroException: 

static int Calc (int x) { return 10 / x; }

static void Main()
{
	int y = Calc (0);
	Console.WriteLine (y);
}

Catching the Exception

static int Calc (int x) { return 10 / x; }

static void Main()
{
	try
	{
		int y = Calc (0);
		Console.WriteLine (y);
	}
	catch (DivideByZeroException ex)
	{
		Console.WriteLine ("x cannot be zero");
	}
	Console.WriteLine ("program completed");
}

The catch Clause

Specifies what type of exception to catch, can be from System.Exception or subclass of System.Exception. You can handle multiple exception types with multiple catch clauses.

static void Main() { Main ("one"); }

static void Main (params 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!");
	}
}

static int Calc (int x) { return 10 / x; }

Exception Filters

You can specify an exception filter in a catch clause by adding a when clause.

try
{
	new WebClient().DownloadString ("http://thisDoesNotExist");
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout)
{
	"Timeout!".Dump();
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.NameResolutionFailure)
{
	"Name resolution failure!".Dump();
}
catch (WebException ex) 
{
	$"Some other failure: {ex.Status}".Dump();
}

The finally Block

Used for code cleanup, executes after a catch block finishes or after control leaves the try block because of a jump statement or after the try block ends. The only things that can defeat a finally block are infinite loop or process ending abruptly.

The using statement

Implements System.IDisposable which defines a single parameterless method named Dispose to clean up the resources.

The using statement provides an elegant syntax for calling Dispose on an IDisposable object with in finally block.

using (StreamReader reader = File.OpenText("file.txt"))
{ ... }

is equivalent to:

{
  StreamReader reader = File.OpenText("file.txt");
  try
  {
    ...
  }
  finally
  {
     if(reader != null)
       ((IDisposable)reader).Dispose();
  }
}

Throwing Exceptions

Exceptions can be thrown either by the runtime or in user code.

static void Display (string name)
{
	if (name == null)
		throw new ArgumentNullException (nameof (name));

	Console.WriteLine (name);
}

static void Main()
{
	try
	{
		Display (null);
	}
	catch (ArgumentNullException ex)
	{
		Console.WriteLine ("Caught the exception");
	}
}

Rethrowing an exception

Rethrowing lets you back out of handling an exception should circumstances turn out to be outside what you expected.

string s = null;

using (WebClient wc = new WebClient())
	try { s = wc.DownloadString ("http://www.albahari.com/nutshell/");  }
	catch (WebException ex)
	{
		if (ex.Status == WebExceptionStatus.NameResolutionFailure)
			Console.WriteLine ("Bad domain name");
		else
			throw;     // Can’t handle other sorts of WebException, so rethrow
	}

s.Dump();

Using exception filter:

catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout)
{
  Console.WriteLine("Timeout");
}

Throwing more specific exception type:

try
{
  ... // Parse a DateTime from XML element data
}
catch (FormatException ex)
{
   throw new XmlException ("Invalid DateTime", ex);
}

Key Properties of System.Exception

StackTrace

A string representing all the methods that are called from the origin of the exception to the catch block.

Message

A string with a description of the error.

InnerException

The inner exception that caused the outer exception.

Common Exception Types

System.ArgumentException

Thrown when a function is called with a bogus argument. This generally indicates a program bug.

System.ArgumentNullException

Subclass of ArgumentException that’s thrown when a function argument is (unexpectedly) null.

System.ArgumentOutOfRangeException

Subclass of ArgumentException that’s thrown when a argument is too big or too small. Eg 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 sucessfully execute regardless of any particular argument values.

System.NotSupportedException

Thrown to indicate that a particular function is not supported. Eg calling Add method on a collectionwhich is IsReadOnly.

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.

System.NullReferenceException

Thrown when you attempt to access a member of an object whose value is null.

The TryXXX Method Pattern

Offers both for exception: Parse and TryParse.

static void Main()
{
	bool result;
	TryToBoolean ("Bad", out result).Dump ("Successful");
	result = ToBoolean ("Bad");		// throws Exception
}

public static bool ToBoolean (string text)
{
	bool returnValue;
	if (!TryToBoolean (text, out returnValue))
		throw new FormatException ("Cannot parse to Boolean");
	return returnValue;
}

public static bool TryToBoolean (string text, out bool result)
{
	text = text.Trim().ToUpperInvariant();	
	if (text == "TRUE" || text == "YES" || text == "Y")
	{
		result = true;
		return true;
	}
	if (text == "FALSE" || text == "NO" || text == "N")
	{
		result = false;
		return true;
	}
	result = false;
	return false;
}

The Atomicity Pattern

static void Main()
{
	Accumulator a = new Accumulator();
	try
	{
		a.Add (4, 5);             // a.Total is now 9
		a.Add (1, int.MaxValue);  // Will cause OverflowException
	}
	catch (OverflowException)
	{
		Console.WriteLine (a.Total);  // a.Total is still 9
	}
}

public class Accumulator
{
	public int Total { get; private set; }
	
	public void Add (params int[] ints)
	{
		bool success = false;
		int totalSnapshot = Total;
		try
		{
			foreach (int i in ints)
			{
				checked { Total += i; }
			}
			success = true;
		}
		finally
		{
			if (! success)
				Total = totalSnapshot;
		}
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *