21

In C#, what is the difference Between 'Catch', 'Catch (Exception)', and 'Catch(Exception e)' ?

The MSDN article on try-catch uses 2 of them in its examples, but doesn't explain the difference in usage purposes.

try
{}
catch 
{}

try 
{}
catch (Exception)
{}

try
{}
catch(Exception e)
{}

How do these differ? Which ones catch all exceptions, and which ones catch specific exceptions?

4

7 回答 7

46

还没有人提到这个问题的历史方面。

在 .NET 中,抛出一个不是从 .NET 派生的对象是合法的Exception。(这在 C# 中是不合法的,但在其他一些托管语言中是合法的。)许多人不知道这一事实,但它是合法的。由于这太疯狂了,在 .NET 2.0 中默认值已更改:如果您尝试抛出不是异常的东西,那么它会自动包装在RuntimeWrappedException显然异常的类中。然后抛出该对象。

由于这种奇怪的情况,在 C# 1.0 中,经常会看到同时执行这两种操作的代码:

try
{ do something }
catch(Exception) 
{ handle the exception }
catch
{ handle the thrown non-exception }

实际上存在安全性和正确性问题;在某些情况下,出于安全原因,您必须抓住任何抛出的东西(可能要重新抛出它),人们会合理地认为catch(Exception)抓住了所有东西,但事实并非如此。

幸运的是,自从 .NET 2.0 以来,事情变得更加明智。您可以依赖catch {},catch(Exception) {}catch(Exception ex) {}在您需要时捕获所有内容。

最后:如果出于某种疯狂的原因你想打开 C# 1.0 的行为,你可以把

[assembly:System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows = false)]

在你的程序中。

于 2013-06-12T19:51:00.610 回答
24

简而言之...

Catch没有参数将收到任何异常,但无法提供解决方法。

Catch (Exception)基本上会做同样的事情,因为您已经指定了根Exception类型。与之相反,Catch (IOException)它只会捕获IOException类型。

Catch (Exception ex)捕获所有异常并提供一种通过ex变量解决它的方法。

阅读更多:http: //msdn.microsoft.com/en-us/library/ms173160.aspx

于 2013-06-12T19:41:10.493 回答
9

第一个版本捕获从 Exception 类派生的所有异常。

第二个版本捕获指定的异常。

第三个版本使用声明的名称捕获指定的异常。然后在 catch 块中你可以使用这个对象,例如,查看完整的错误:e.ToString();

在这里阅读更多。

于 2013-06-12T19:39:09.570 回答
6

它们基本上都做同样的事情,不同之处在于它们提供的有关错误的信息量。

catch (foo ex) {}将过滤掉所有异常,除了那些可以强制转换为 type 的异常foo。它还为您提供了错误的实例供您处理。

catch (foo) {}和上面一样,但它没有给你异常的实例。您将知道异常的类型,但无法从中读取信息。

请注意,在这两种情况下,如果异常的类型是Exception,它们将捕获所有异常。

catch {}捕获所有异常。您不知道它捕获的类型,并且您无法访问该实例。

您可以根据捕获异常所需的信息量来选择使用哪一个。

无论您使用哪一个,您都可以使用命令throw;(不带参数)将捕获的异常向前传递。

于 2013-06-12T19:43:59.343 回答
3

在你的例子中,什么都没有,因为你没有做任何例外的事情。但要澄清...

  • 这会捕获所有内容,但除此之外什么都不做。

    catch {}
    

    这仅在您想说保证从方法返回时才有用。

  • 这仅捕获类型的异常Exception(即一切),但对异常不执行任何操作。

    catch (Exception) {}
    

    如果您想通过指定要处理的类型来限制捕获的异常类型,这很有用。任何其他异常都会在调用堆栈中冒泡,直到找到合适的处理程序。

  • 这仅捕获类型的异常Exception(即一切)并且可以对异常执行某些操作,但碰巧什么也不做

    catch (Exception ex) {}
    

    这种技术为您提供了更多选择。您可以记录异常、检查InnerException等。您可以再次指定要处理的异常类型。

除非您以某种方式重新抛出异常,否则所有这些都是不好的做法。一般来说,您应该只捕获您可以有意义地处理的异常并允许其他任何事情冒泡。

于 2013-06-12T19:41:04.533 回答
1

添加 catch(Exception e) 将使您能够访问 Exception 对象,该对象包含有关所引发异常的详细信息,例如其 Message 和 StackTrace;记录此信息以帮助诊断错误很有用。一个简单的 catch 而不声明您尝试捕获的异常不会让您访问异常对象。

此外,捕获基本异常通常被认为是不好的做法,因为它太通用了,并且在可能的情况下,您应该始终首先处理特定异常。例如,如果您正在处理文件,您可能会考虑以下 try/catch 块:

try{
    //open your file and read/write from it here
}catch(FileNotFoundException fe){
    //log the message
    Log(fe.Message);
}catch(Exception e){
    //you can catch a general exception at the end if you must
}finally{
    //close your file
}
于 2013-06-12T19:50:11.750 回答
1

在最高级别,它们都是一样的;他们都捕获异常。

但是为了进一步深入研究,在第一种情况下,您正在捕获异常并且什么都不做(您没有定义的类型)。在第二个示例中,您正在捕获 Exception 类型的异常。在上一个示例中,您捕获的异常类型与示例 2 中的相同,但现在您将异常放入一个变量中,该变量允许您在 MessageBox 中显示它,或者:

e.Message

同样重要的是要注意异常是分层的意思,如果您在同一个 try/catch 块中捕获多种类型的异常,您将从最具体的异常类型转到最一般的异常类型。像这样:

try {
}
catch (SqlException sqlExc) {
}
catch (Exception exc) {
}
于 2013-06-12T19:55:09.113 回答