C#使用try..catch块捕获异常

C#使用try..catch块捕获异常,c#,exception-handling,try-catch,block,C#,Exception Handling,Try Catch,Block,我是C#的新手,希望更好地理解异常捕获。这些问题可能是愚蠢的noob问题。他们对我很重要,我提前道歉 例如,在System.IO路径类GetFullPath中,可以引发五个异常:ArgumentException、SecurityException、ArgumentNullException、NotSupportedException和PathTooLongException。我理解,必须组织捕获块,以便首先捕获最特定的异常,最后捕获最一般的异常 问题1: 当MSDN提供关于类引发的可能异常的信

我是C#的新手,希望更好地理解异常捕获。这些问题可能是愚蠢的noob问题。他们对我很重要,我提前道歉

例如,在System.IO路径类GetFullPath中,可以引发五个异常:ArgumentException、SecurityException、ArgumentNullException、NotSupportedException和PathTooLongException。我理解,必须组织捕获块,以便首先捕获最特定的异常,最后捕获最一般的异常

问题1: 当MSDN提供关于类引发的可能异常的信息时,我如何知道哪个异常最具体,哪个最不具体?换句话说,我如何根据MSDN提供的信息确定从最具体到最不具体的异常顺序

问题2: 我是否需要明确地捕获所有异常,或者只使用最通用的异常也会捕获所有其他异常?例如,仍然使用Path类,我是否需要执行

try { ... }
catch(System.ArgumentNullException ane) { ... }
catch(System.NotSupportedException nse) { ... }
catch(System.IO.PathTooLongException ple) { ... }
catch(System.IO.SecurityException se) { ... }
catch(System.ArgumentException ae) { ... }
还是一个简单的

catch(System.ArgumentException ae) { ... }
捕获所有异常

问题3: 在bool方法中执行以下操作的语法结构是否正确

try
{
  ... ;
  return true;
}
catch(System.ArgumentException ae)
{
  ... ;
  return false;
}
问题1:

在每个异常的MSDN文档中,您可以看到其继承链。这会告诉你哪些更具体(链条越低,它们就越具体)

您还可以在Visual Studio对象浏览器中看到此信息

问题2:

捕捉可以处理的异常是一种很好的做法。如果你不能合理地做任何例外的事情,那就让它冒泡吧

一般来说,tt最好先捕获更具体的异常

您还需要查看不同的继承链,并决定要捕获哪些异常。例如,只是做:

catch(System.ArgumentException ae) { ... }
不会捕获
System.IO.SecurityException
,因为
System.IO.SecurityException
不会从
System.ArgumentException
继承

问题3:

是的,这是有效的语法

但我不认为这是一个好的练习。如果这是一个例外情况,最好让例外冒泡起来。建议的设计将导致忽略异常,任何使用此方法编程的人都需要检查返回值(他们可能会忘记该值)。

一些指导原则:

  • 通过查看MSDN上异常的继承继承继承权,可以判断异常的“特殊性”。如果它们派生自公共基类,则基类异常就不那么具体。一个常见的例子是IOException,它是与I/O相关的几个更具体异常的基类

  • 您通常不应该捕获使用异常,如ArgumentException、ArgumentNullException、NotSupportedException等。如果抛出这些异常,则它们表示代码中必须修复的错误。在关闭应用程序之前,这些错误应该只被您的“最终捕获”捕获,以便记录并格式化错误以便更友好地显示


  • 针对该评论:

    在验证输入之后捕获使用异常是一个坏习惯,尤其是通过捕获
    异常
    (因为这会掩盖其他意外的异常类型)来捕获时。提前验证要好得多。不幸的是,这个特定的方法(Path.GetFullPath)在设计时没有考虑到这些准则,因此您需要处理ArgumentException、NotSupportedException和PathTooLongException来验证用户输入。您可以在一个catch子句中这样做:

    try
    {
         //Call Path.GetFullPath somewhere in here
    }
    catch (Exception ex)
    {
         if (ex is ArgumentException || ex is NotSupportedException || ex is PathTooLongException)
         {
              //Your handling here
         }
         else
         {
              throw;
         }
    }
    
    您希望使try块中的代码尽可能短,因为除了Path.GetFullPath可能引发的使用异常之外,您不希望无意中抑制其他使用异常。不过,实际上您可能希望单独处理每个异常,因为您可以利用它们之间的差异向用户提供有用的反馈,以了解他们做错了什么

    1)任何异常的特定性都基于其从更一般的基类异常继承的层次结构

    2) 您可以按如下所示使用通用的“包罗万象”:

    try
    {
        ...
    }
    catch (System.Exception ex)
    {
        ...
    }
    
    3) 是的,这很好,尽管您可能希望在您已经有了更具体的
    ArgumentException
    之后,获得我(2)的答案中所示的全面信息。

    1)大多数情况下,您可以使用名称来判断。(例如,ArgumentNullException继承自ArgumentException)。当您不能通过名称来区分时,您可以查看文档或对象浏览器,它会给出继承树

    2) 你会根据你的需要特别钓到哪些鱼。许多人会告诉您,即使获得ArgumentException或ArgumentNullException,也意味着作为开发人员,您无法验证调用中更高层的内容

    3) 如果发生异常,通常不希望返回任何内容-异常本身意味着方法无法正确完成,这意味着无论如何都不能为返回值提供良好的数据。但也有例外,所以YMMV

  • 当您将异常的名称指定为catch(System.ArgumentNullExcpetion)时,它将只捕获这些类型。您可以检查msdn上异常文档页面上的继承描述,以检查更普遍的异常,您只需要担心这些

  • 您可以捕获最常见的异常,但有时在编写和调试程序时,特定的异常可能更有用,它可以帮助您了解引发的异常类型

  • 是的,可以使用这种语法


  • 答案是:除非你知道自己能处理,否则不要抓住任何一个(也就是说,除非你能真正解决问题)。这个问题是重复的,我会努力找出问题的答案,这是重复的