C#异常处理,要使用哪个catch子句

本文关键字:catch 子句 异常处理 | 更新日期: 2023-09-27 18:20:38

可能重复:
在c#中捕获特定异常与一般异常

下面是的一个示例方法

private static void outputDictionaryContentsByDescending(Dictionary<string, int> list)
{
    try
    {
        //Outputs entire list in descending order
        foreach (KeyValuePair<string, int> pair in list.OrderByDescending(key => key.Value))
        {
            Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
        }
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message, "Error detected", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

我想知道除了Exception之外,还应该使用什么异常子句,以及使用更具体的catch子句是否有优势。

编辑:好的,感谢大家

C#异常处理,要使用哪个catch子句

在您的语句中捕获个别类型的异常将使您能够以不同的方式处理每种异常。

Exception的一揽子规则可能有助于记录和重新思考异常,但对于实际处理您可能能够恢复的异常来说,它并不是最好的。

try
{
    // open a file specified by the user
}
catch(FileNotFoundException ex)
{
    // notify user and re-prompt for file
}
catch(UnauthorizedAccessException ex)
{
    // inform user they don't have access, either re-prompt or close dialog
}
catch(Exception ex)
{
    Logger.LogException(ex);
    throw;
}

您应该只捕获您所期望的代码可能抛出的异常。这样,如果它抛出了你没有预料到的东西,它可能是关键的东西;应该弹出调用堆栈并可能导致应用程序崩溃的东西;或者一些你没有想到的事情。

例如,您可能希望处理I/O代码引发的IOException,以便将问题转发给用户。然而,相同的操作可能会抛出更关键的东西,例如AccessViolationException。在这种情况下,您可能希望程序终止,或者以不同的方式处理问题。

一般异常处理应该只在您不关心发生了什么错误,并且随后不希望它影响流程的其余部分的情况下使用

我在您的示例中看到的异常的唯一潜在原因是list为空。OrderByDescending()应该返回一个空的IEnumerable<>,而不是一个空引用。

如果我读对了,捕捉NullReferenceException:可能更有意义

try
{
...
} catch (NullReferenceException exception)
{
  MessageBox.Show(...);
}

但是,这实际上取决于您的应用程序的需要。如果您的意图只是提醒用户或记录所有异常,那么捕获Exception类就可以了。如果您需要对不同类型的异常进行特殊处理,例如发送电子邮件警报而不仅仅是记录消息,那么使用特定的异常类型是有意义的:

try
{
} 
catch(NullReferenceException e)
{
//...
} 
catch(StackOverflowException e)
{
//...
}
catch(Exception e)
{
/// generic exception handler
}

使用哪个异常真正取决于try块中的代码。通常,您希望捕获可以执行某些操作的异常,并让您无权处理的异常转移到代码的高层,在那里您可以执行一些操作。我看到人们犯的最常见的错误之一是试图抓住他们没有能力处理的错误。

例如

Void ChoseFile()
{
     try
     { 
         string FileName = GetInputFile()
     }    
     catch( InvalidFileSelectedException ex)
     { 
         //In this case we have some application specific exception 
         //There may be a business logic failure we have some ability 
         //to infomr the user or do an action that makes sense  
     }
     catch(FileNotFoundException exfilenot found)
     { 
         //In this case we can do somthing different the the above 
     }
     catch(Exception ) 
     { 
         //Normal I would not use this case we have an error we don't know what to do 
         //with. We may not have a usefull action.  At best we can log this exception                               
         // and rethrow it to a higher level of the application that can inform the user
         // fail the attempted action.  Catching here would only suppress the failure.
      }
} 

您应该始终使用尽可能特定的类捕获异常。

如果你知道如果一个文件被锁定了该怎么办,但你认为所有其他错误都是意外的,不可能处理,那么你应该抓住System.IO.IOException并处理这个错误。您应该只捕获Exception(或仅捕获catch {)以正常退出。

由于您正在处理字典。。那么你想看看这两个例外

  • keyValuePair的键是null引用(在Visual Basic中为Nothing)。

  • ArgumentException字典中已存在具有相同关键字的元素(TKey,TValue)。

    KekValuePair异常这是从MSDN网站

使用您可能期望但仍然无法阻止的异常类型,并且您可以充分处理该异常类型。让任何其他东西冒出来,到达可能预期或可以处理的地方。

在您的情况下,如果字典为null,我可能会遇到NullReferenceException但我不会抓住它。这是我可以验证的东西,而不是

if (dictionary != null) 

因此,没有理由允许出现异常情况。永远不要对控制流使用异常,并根据已知原因进行验证。

某些类/方法会根据错误抛出不同的异常。例如,您可能正在使用File类将数据写入文件。您可以为可以从中恢复的异常类型编写多个Catch语句,并编写一个通用的exception Catch来记录和弹出任何无法从中恢复到的异常。

使用Exception可以捕获所有异常。如果使用IOException或StackOverflowException,则只能捕获该类型的错误。

被异常捕获的StackOverflowException仍然保存相同的消息、堆栈跟踪等。

异常处理理念我相信你可以找到许多其他哲学

代码防御。捕获异常比从一开始就防止错误更昂贵。

不要抓住一个异常而不处理它。你可能会花很多小时试图找到一个被抑制的错误。

请记录您发现的错误。这有助于分析问题。您可以检查是否有多个用户有相同的问题我更喜欢数据库进行日志记录,但平面文件或事件日志也很合适。数据库解决方案最容易分析,但可能会引入额外的错误。

如果错误是由用户输入的错误数据引起的,请将问题通知用户并允许他们重试。如果他们无法解决问题,一定要留出逃生路线。

尽可能靠近源捕获错误这可以是数据库过程、数据访问层(DAL)中的方法或某个其他位置。

处理异常与捕获异常不同。您可能需要重新引发异常,以便在堆栈的更高级别或UI中处理它。

至少可以通过两种方式重新处理异常。throw本身不会改变堆栈。throw-ex确实对堆栈进行了更改或添加,但没有任何好处。

有时候,最好不要抓住一个例外,而是让它冒出来。

如果您正在编写没有用户界面(UI)的服务(web或windows),则应始终记录错误。同样,这是为了让人们可以分析日志或数据库文件,以确定发生了什么。

你总是想让别人知道发生了错误。

一个try块有很多catch语句会使代码更难维护,尤其是在catch块中的逻辑很复杂的情况下。相反,代码是防御性的。

请记住,您可以在catch块中尝试catch块。

另外,不要忘记在适当的地方使用finally块。例如,关闭数据库连接或文件句柄等。

HTHHarv