.NET 2.0 trycatch and trycatch(Exception ex)

One thing that I found rather interesting about .NET 2 that's different from .NET v1 is how v2 handles non-exception throwables differently.

First, a little background...

In case you don't know, the following two pieces of code are completely different.

try {
    Thrower.Start( );
}
catch (System.Exception ex) {
    System.Console.Write("Error!");
}
try {
    Thrower.Start( );
}
catch {
    System.Console.Write("Error!");
}

The difference is not that the first catches exceptions from unmanaged code and the second second doesn't, the first actually does catch those exceptions. The difference is also a bit more important than the mere fact that in the first one case we capturing the exception data in an exception type and in the other we aren't. The real difference stems from the fact that that in .NET you can throw things other than exceptions and in v1 you used the latter code to catch those non-exception throwables.

Here's an example of how to throw a non-exception. Yeah, you basically have to use the IL, or a compiler that doesn't check for this stuff.

// ThrowerLib.il
.assembly ThrowerLib { }

.class public Thrower {
    .method static public void Start( ) {
        ldstr "Oops"
        throw
        ret
    }
}

Here we are throwing "Oops". That's obviously a string, not something derived from System.Exception. In v1 you could use try{}catch(Exception ex) {} as a catch all for all exceptions, but that would not catch this error as it's not an exception. To catch this, you would also have a catch{} at the end.

OK, so how's v2 different? In this world, the non-exception item thrown is wrapped up in a real exception. So, in .NET v2 you can actually use your normal try {} catch(Exception ex){ } to also catch these non-exception throwables as well.

They are actually thrown as a RuntimeWrappedException. So the following app compiled an run in .NET v1 would explode into pieces, but would would gracefully end in .NET v2.

// ThrowerLib.il
.assembly ThrowerLib { }

.class public Thrower {
     .method static public void ThrowException( ) {
         ldstr "ThrowException exception from the IL world!"
         newobj instance void [mscorlib]System.Exception::.ctor(string)
         throw
         ret
     }

     .method static public void ThrowString( ) {
         ldstr "Weird exception!"
         throw
         ret
     }
}
// ThrowerHarness.cs
namespace ThrowerExample
{
    class ThrowerHarness
    {
        static void Main(string[] args) {
            try {
                Thrower.ThrowException( );
            }
            catch (System.Exception ex) {
                System.Console.WriteLine("System.Exception error: " + ex.Message);
            }
            catch {
                System.Console.WriteLine("Non System.Exception based error.");
            }

            try {
                Thrower.ThrowString( );
            }
            catch (System.Exception ex) {
                System.Console.WriteLine("System.Exception error: " + ex.Message);
            }
            catch {
                System.Console.WriteLine("Non System.Exception based error.");
            }
        }
    }
}