10

以下 catch 块有什么区别?

try
{
    ...
}
catch
{
    ...
}

try
{
    ...
}
catch(Exception)
{
    ...
}

我意识到,在任何一种情况下,异常实例都不可用,但是有什么我可以用一个不能用另一个做的吗?

4

6 回答 6

7

catch不带参数将捕获不符合 CLS 的异常,不像catch (Exception).

于 2011-03-17T21:27:30.233 回答
7

它们几乎相同。

从 C# 语言规范,第 8.10 节:

某些编程语言可能支持无法表示为派生自 System.Exception 的对象的异常,尽管 C# 代码永远不会生成此类异常。通用的 catch 子句可用于捕获此类异常。因此,一般的 catch 子句在语义上与指定类型 System.Exception 的子句不同,因为前者也可以捕获来自其他语言的异常。

请注意,虽然 C# 区分了这两者,但它们实际上与 .NET 2.0 相同,如本博客所述:

由于最近 2.0 CLR 的更改,如果您的代码决定在某处抛出一个 int (System.Int32),CLR 现在将使用 RuntimeWrappedException 包装它,并且编译器已更新为您提供警告上面的第二个子句现在是死代码

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

对于 CLR 如何知道为您的程序集执行此操作,您会注意到编译器现在向您的程序集添加了一个 RuntimeCompatibilityAttribute,告诉它:
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = {property bool 'WrapNonExceptionThrows' = bool(true)}

于 2011-03-17T21:26:35.353 回答
4

为什么 catch(Exception)/empty catch 不好

空的 catch 语句可能同样糟糕,具体取决于您的语言生成的 MSIL 代码。C# 将一个空的 catch 语句转换为 catch(System.Object) ,这意味着您最终会捕获所有异常 - 甚至是不符合 CLS 的异常。VB 表现更好,将空的 catch 语句转换为 catch e as System.Exception,这限制了您捕获符合 CLS 的异常。

于 2011-03-17T21:28:38.287 回答
3

如果您查看生成的 IL,这里有区别:

catch(Exception){}:

catch [mscorlib]System.Exception
{}

并且很简单:

catch{}:

catch [mscorlib]System.Object
{}

因此,理论上,如果您创建的语言可以具有不继承自 System.Exception 的异常,那么就会有所不同...

于 2011-03-17T21:34:31.983 回答
1

非 CLS 遵循语言(如 C++/CLI)可以抛出不是从 System.Exception 类派生的对象。第一个代码示例将允许您在 catch 块中执行代码,但您无法检查抛出的对象本身。这几乎从来都不是问题,但它可能是。

于 2011-03-17T21:28:07.383 回答
0

我不相信有区别,像 Resharper 这样的工具会告诉你catch(Exception)在第二种情况下是多余的,除非你之前还插入了其他catch(SomeSubclassException)异常处理块,Exception以便为其他异常条件应用不同的异常处理逻辑。

于 2011-03-17T21:27:08.347 回答