【问题标题】:What is the difference between the 3 catch block variants in C# ( 'Catch', 'Catch (Exception)', and 'Catch(Exception e)' )?C# 中的 3 个 catch 块变体('Catch'、'Catch (Exception)' 和 'Catch(Exception e)')有什么区别?
【发布时间】:2013-06-09 01:22:41
【问题描述】:

在 C# 中,'Catch'、'Catch (Exception)' 和 'Catch(Exception e)' 有什么区别?

MSDN article on try-catch 在其示例中使用了其中的 2 个,但没有说明使用目的的区别。

try
{}
catch 
{}

try 
{}
catch (Exception)
{}

try
{}
catch(Exception e)
{}

这些有何不同?哪些捕获所有异常,哪些捕获特定异常?

【问题讨论】:

标签: c# visual-studio-2010 exception try-catch


【解决方案1】:

第一个版本捕获所有源自 Exception 类的异常。

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

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

阅读更多here

【讨论】:

  • 其实你会使用e.Message
  • @DonBoitnott:不,您不应该使用 e.Message。这只是用户的“漂亮”消息。 e.ToString() 显示所有信息,包括内部异常。
  • @JohnSaunders 你指的是“堆栈跟踪”吗?如果是这样,那我就同意了。
  • 另请注意,版本捕获Exception 类型或任何从Exception派生的类型。
  • @DonBoitnott:不仅仅是 e.StackTrace。 ToString 会显示内部异常、服务器端异常等
【解决方案2】:

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

  • 这会捕获所有内容,但对异常不执行任何操作。

    catch {}
    

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

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

    catch (Exception) {}
    

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

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

    catch (Exception ex) {}
    

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

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

【讨论】:

  • 该语言不允许 catch 块出现在另一个 catch 块之后,该块已经处理了此 catch 将处理的每种类型。但它确实允许catch (Exception) { ... } catch { ... },据说最后一个块是无法访问的。根据this answer,C# 以外的某些语言可能会“抛出”一个不是System.Exception 的对象。这是真的吗?我听说在那种情况下,外来对象毕竟会被运行时包裹在 Exception 中,但这是正确的吗?
  • Lippert 刚刚在他的回答中解释了这一点。
【解决方案3】:

总之……

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

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

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

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

【讨论】:

    【解决方案4】:

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

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

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

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

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

    您可以根据在捕获异常时需要多少信息来选择使用哪一个。

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

    【讨论】:

      【解决方案5】:

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

      此外,捕获基本异常通常被认为是不好的做法,因为它过于笼统,并且在可能的情况下,您应该始终首先处理特定异常。例如,如果您正在处理文件,您可能会考虑以下 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
      }
      

      【讨论】:

        【解决方案6】:

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

        在 .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) 抓住了所有东西,但事实并非如此。 p>

        幸运的是,从 .NET 2.0 开始,事情变得更加明智;您可以依靠catch {}catch(Exception) {}catch(Exception ex) {} 来获取所需的一切。

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

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

        在你的程序中。

        【讨论】:

        • +1 因为你几乎没有任何声誉。哦,还有历史课:)
        • 对于自 2.0 版以来的 .NET Compact Framework 是否也是如此?
        • @Thomas:这是一个问答网站。如果您有任何问题,请将其作为问题发布,然后会有人回答。我注意到“框架 X 是否支持功能 Y?”是一个你可以通过尝试来回答的问题。
        【解决方案7】:

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

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

        e.Message
        

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

        try {
        }
        catch (SqlException sqlExc) {
        }
        catch (Exception exc) {
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-12
          • 2020-07-26
          • 1970-01-01
          • 2012-06-04
          • 1970-01-01
          • 2014-03-18
          • 2021-04-17
          相关资源
          最近更新 更多