以下 catch 块有什么区别?
try
{
...
}
catch
{
...
}
和
try
{
...
}
catch(Exception)
{
...
}
我意识到,在任何一种情况下,异常实例都不可用,但是有什么我可以用一个不能用另一个做的吗?
以下 catch 块有什么区别?
try
{
...
}
catch
{
...
}
和
try
{
...
}
catch(Exception)
{
...
}
我意识到,在任何一种情况下,异常实例都不可用,但是有什么我可以用一个不能用另一个做的吗?
catch
不带参数将捕获不符合 CLS 的异常,不像catch (Exception)
.
它们几乎相同。
从 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)}
从为什么 catch(Exception)/empty catch 不好
空的 catch 语句可能同样糟糕,具体取决于您的语言生成的 MSIL 代码。C# 将一个空的 catch 语句转换为 catch(System.Object) ,这意味着您最终会捕获所有异常 - 甚至是不符合 CLS 的异常。VB 表现更好,将空的 catch 语句转换为 catch e as System.Exception,这限制了您捕获符合 CLS 的异常。
如果您查看生成的 IL,这里有区别:
catch(Exception){}:
catch [mscorlib]System.Exception
{}
并且很简单:
catch{}:
catch [mscorlib]System.Object
{}
因此,理论上,如果您创建的语言可以具有不继承自 System.Exception 的异常,那么就会有所不同...
非 CLS 遵循语言(如 C++/CLI)可以抛出不是从 System.Exception 类派生的对象。第一个代码示例将允许您在 catch 块中执行代码,但您无法检查抛出的对象本身。这几乎从来都不是问题,但它可能是。
我不相信有区别,像 Resharper 这样的工具会告诉你catch(Exception)
在第二种情况下是多余的,除非你之前还插入了其他catch(SomeSubclassException)
异常处理块,Exception
以便为其他异常条件应用不同的异常处理逻辑。