8

The CLS is more restrictive than the CLR, which would allow you to throw and catch any type of objects (even value types). Why?

Also what would happen if some non CLS-compliant code threw a non Exception derived object while called by a CLS compliant code?

UPDATE Second question answered by @Marton. Still wonder why.

MatteoSp
  • 2,940
  • 5
  • 28
  • 36
  • down-voting without explaining should be prohibited – MatteoSp May 07 '15 at 16:17
  • 4
    The CLS rule exist so exceptions thrown by code written in one language can be reasonably caught by code written in another. The CLI spec doesn't exclude the possibility that it *might* be useful in some kind of obscure language to throw something else. Surely you'll have a hard time finding an example of such a language. What happens is somewhat obvious, the program crashes with no way to catch or diagnose the exception. – Hans Passant May 07 '15 at 16:59
  • So it turns out is not so obvious, right? – MatteoSp May 07 '15 at 18:49

2 Answers2

5

CLS specifies a minimum set of language features needed by many applications in such a way that if an API uses only those features, it can be consumed by any CLS-compliant language. So naturally it is more restrictive than the CLR. On the other hand, the CLR is deigned to handle manged code from any CLI-compliant language.

An example of a language that allows throwing non-CLS-compliant exceptions (those not derived from System.Exception) is C++/CLI. This language was designed to be a superset of plain C++ which includes the ability to throw exceptions of any type. This could be the only good reason to throw non-CLS exceptions.

Regarding the second question. A non-CLS exception, when thrown, different things happen in different cases:

  • If CLR 1.X is managing the execution of the code, the exception propagates as is. In languages that only support CLS exceptions (C#), the exception can only be caught by a parameterless catch block. There is no easy way to access the exception and a stack trace will not be recorded.
  • On CLR 2.0 and later, the CLR internally always wraps the exception into a System.Runtime.CompilerServices.RuntimeWrappedException which maintains a field of type Object that references the original exception. This allows a stack trace to be recorded. When it propagates up the stack:

    1. If the System.Runtime.CompilerServices.RuntimeCompatibilityAttribute attribute was applied on the assembly of the function in which the CLR is looking for a matching catch block and WrapNonExceptionThrows set to true (automatically applied by the Visual C# and Basic compilers), then the exception continues to be wrapped.

    2. Otherwise, if the attribute was not applied or if WrapNonExceptionThrows was set to false, the exception is unwrapped every time a catch block is examined for matching.

Edit

In C#, in the first bullet above and the second case of the second bullet, the only way to catch a non-CLS exception is by using a parameterless catch block.

Hadi Brais
  • 22,259
  • 3
  • 54
  • 95
2

The why part I cannot answer, but the second part I can:

what would happen if some non CLS-compliant code threw a non Exception derived object while called by a CLS compliant code?

If you throw a non-Exception-derived object, it will still be caught by CLS-compliant code, since it will be wrapped into a RuntimeWrappedException.

(The source article is worth a read for more details.)

molnarm
  • 9,856
  • 2
  • 42
  • 60