为什么CLS规定必须抛出/捕获派生自Exception类的对象?

8

CLS比CLR更加严格,这意味着您只能抛出和捕获特定类型的对象(即引用类型)。为什么呢?

如果一些不符合CLS标准的代码在由符合CLS标准的代码调用时抛出了一个非Exception派生的对象会发生什么?

更新:@Marton已经回答了第二个问题。但是我还是想知道为什么。


禁止未解释的负评。 - MatteoSp
4
CLS规则的存在是为了让用一种语言编写的代码抛出的异常可以被用另一种语言编写的代码合理地捕获。CLI规范并不排除在某些晦涩难懂的语言中抛出其他异常可能有用的可能性,但你很难找到这样一种语言的例子。如果出现这种情况,程序会崩溃,无法捕获或诊断异常。 - Hans Passant
所以事实证明这并不是那么显而易见的,对吧? - MatteoSp
2个回答

5
CLS指定了许多应用程序所需的最小语言特性。如果API仅使用这些特性,它就可以被任何CLS兼容的语言使用。因此,它比CLR更加严格。另一方面,CLR旨在处理来自任何CLI兼容语言的托管代码。
一个允许抛出非CLS兼容异常(不派生自System.Exception)的语言的例子是C++/CLI。该语言被设计为普通C++的超集,包括抛出任何类型的异常的能力。这可能是抛出非CLS异常的唯一好理由。
关于第二个问题。抛出非CLS异常时,在不同情况下会发生不同的事情:
- 如果CLR 1.X管理代码执行,则异常会按原样传播。在仅支持CLS异常(如C#)的语言中,异常只能被无参数catch块捕获。没有简单的方法来访问异常,也不会记录堆栈跟踪。 - 在CLR 2.0及更高版本中,CLR内部始终将异常包装到System.Runtime.CompilerServices.RuntimeWrappedException中,该异常维护一个引用原始异常的Object类型字段。这允许记录堆栈跟踪。当它向上传播时: - 如果在CLR正在查找匹配的catch块的函数的程序集上应用了System.Runtime.CompilerServices.RuntimeCompatibilityAttribute属性,并且WrapNonExceptionThrows设置为true(由Visual C#和Basic编译器自动应用),则异常将继续被包装。 - 否则,如果未应用属性或WrapNonExceptionThrows设置为false,则每次检查匹配的catch块时都会取消包装异常。
在C#中,在上述第一条和第二条第二种情况下,捕获非CLS异常的唯一方法是使用无参数catch块。

2
我可以回答第二部分问题:“如果一些不符合CLS标准的代码在被符合CLS标准的代码调用时抛出了一个非Exception派生的对象,会发生什么?” 如果您抛出一个非Exception派生的对象,它仍然会被符合CLS标准的代码捕获,因为它将被包装成一个RuntimeWrappedException。 (源文章值得阅读以获取更多详细信息。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接