One of the recent-ish changes (an excellent one which we can thank CBrumme et al for) is that the CLR will now take those wacky cases where some code (usually C++, C# and VB couldn't do this) that throws an object that's not actually Exception or one of its subclasses, and wrap it up in an exception for you.

Before this change, to *really* catch everything that might be thrown (there was an FxCop rule relating to this), you either had to write a catch { } clause (no access to the thing being thrown) or 2 clauses, catching Exception and then the catch { } clause.

    try

    {

        throw new ArgumentException(

            "Klingon function calls do not have 'parameters' " +

            "- they have 'arguments' " +

            "- and they ALWAYS WIN THEM.");

    }

    catch (Exception ex)

    {

        Console.Error.WriteLine("Doh! - {0}", ex);

    }

    catch

    {

        Console.Error.WriteLine("Doh!");

    }

 

Thanks to a recent change in the 2.0 CLR, if you had code that decided to throw, say, an int (System.Int32) somewhere, the CLR will now wrap it with a RuntimeWrappedException, and the compiler has been updated to give you that warning that the second clause above is now dead code

 

warning CS1058: A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a System.Runtime.CompilerServices.RuntimeWrappedException

 

For how the CLR knows to do this action for your assembly, you'll notice the compiler now adds a RuntimeCompatibilityAttribute to your assemblies telling it to:

.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = {property bool 'WrapNonExceptionThrows' = bool(true)}