Search Forum
(57285 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


              
Printable Version

Exception Handling Changes in C# 2.0
By Mark Michaelis

Charlie Calvert asked me to write some C# posts for MSDN C# Developer Center. This article is the first of a series about the changes from C# 1.0 to C# 2.0. By this I don't mean enhancements (generics, partial classes, etc), but items that would either cause compile errors, create warnings, or change (presumably improve) behavior. I haven't seen much of a comprehensive listing of these changes so I decided to try my hand at coming up with one. In today's post I am going to talk about a change in exception handling.

Consider the following code listing:

using System;
class Program
{
 static void Main()
 {
  try
  {
   Console.WriteLine(
    "Hello. My name is Inigo Montoya.");
  }
  catch(Exception )
  {
   // .
  }
  catch
  {
   Console.WriteLine("UNEXPECTED EXCEPTION");
  }
 }
}
In C# 1.0, this code was perfectly valid. However, in C# 2.0 it results in a warning. Why is that?

An empty catch block (catch{ . }), compiles down to CIL code that is the equivalent of catch(object ){ . }. In other words, an empty catch block in C# is a catch block for any and all types that are thrown as exceptions. (Interestingly, C# doesn't allow you to explicitly code catch(object ){ . }. Therefore, there is no means of catching a non-System.Exception-derived exception and have the exception instance to scrutinize.)

It is perhaps surprising that catch(object ){ . } is needed because C# doesn't allow you to throw an exception that doesn't derive from System.Exception. However, the same restriction does not apply to other languages. C++, for example, can throw an object of any type (whether derived from System.Exception or not). As a result, in C# 1.0, the only way to ensure that all exceptions were caught was to include an empty catch block.

In C# 2.0 the rules improved. Although it is still possible for other languages to throw exceptions of any type, the CLR will wrap all exceptions that do not derive from System.Exception into a System.Runtime.CompilerServices.RuntimeWrappedException object, which does derive from System.Exception. In other words, all exceptions, whether System.Exception-derived or not when they are thrown, will be caught in C# 2.0 code by a catch(Exception ){ . } block.

Therefore, if you follow a catch(Exception ){ . } block by an empty exception block (as shown in the initial code listing), the empty exception block will never execute. All exceptions will be wrapped in the RuntimeWrappedException if they do not derive from System.Exception already and therefore be caught by catch(Exception ){ . }.

One more thing to note: If you wish your code to behave as it did with C# 1.0 in this area, you can add the RuntimeCompatibility assembly attribute as in:

[assembly:System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows = false)]

This will no longer produce the warning since it will also turn off the new CLR 2.0 behavior in which non-System.Exception-derived exceptions are wrapped with RuntimeWrappedException.