Friday, August 18, 2006

CLS and Non-CLS Exception

All programming language for the CLR must support the throwing of Exception derived object because the CLS mandate this. However, the CLR actually allows an instance of any type to be throw, and some programming language will allows code to throw non-CLS-compliant exception object such as a string,Int32 whatever.The c# comiler allows code to throw only Exception-derived objects,whereas code written in IL assembly language and C++/CLI allow code to throw Exception-derived objects as well as objects that are not derived from Exception.

Prior to version 2.0 of the CLR, when programmers wrote catch blocks to catch exception, they were catching CLS-compliant exceptions only. If a c# method called a method written in another language, and that method threw a non-CLS-compliant exception,the C# code would not catch this exception at all.

In version 2.0 of the CLR, Microsoft has introduced a new RuntimeWrappedException class.This class is derived from Exception,so it is a CLS-compliant type.The RuntimeWrappedException class contain a private field of type object.In version 2.0 of the CLR,when non-CLS-compliant exception is throw, the CLR automatically constructs an instance of the RuntimeWrapperdException class and initialize its private field to refer to the object that was actually throw.

private void TestMethod()
{
try
{
// some code
}
catch(Exception e)
{
//Before c# 2.0, this block catches CLS-compliant exception only
// In C# 2.0 this block catches CLS and non CLS compliant exceptions
throw;
}
catch
{
// in all version of C# this block catches CLS and non CLS compliant exceptions
}
}

If the above code is recompiled for CLR 2.0, the second catch block will never execute ,and the c# compiler will indicate this by issuing a warning: "CS1058: A previous catch clause already catches all exceptions.All non- exceptions will be wrapped in a System.Runtime.CompilerServices.RuntimeWrappedException."

There are two ways for developer to migrate code from an eariler version of .Net Framework to version 2.0:

1. You can merge the code from the two catch block into a single catch block.
2. You can tell the CLR that the code in your assembly wants to play by the old rules.That is tell the CLR that you catch blocks should not catch an instance of the new RuntimeWrappedException calss.
[assembly:RuntimeCompatibility(WrapNonExceptionThrows = false)]