为什么要使用特定的异常捕获块

Why use specific exception catch blocks

在下面的代码中,我有一个用于 System.Data.Entity.Infrastructure.DbUpdateException class 异常的 catch 块。

我的问题是,为什么我不能使用 Exception class 来捕获代码中的每一个可能的异常并获取堆栈跟踪?

特定异常类型的优点是什么以及它们在多个 catch 块中的用途?

try
{
    AddAdminUserInput input1 = JsonConvert.DeserializeObject<AddAdminUserInput>(input);
    Foundation_Services_DL_DataEntities Db = DLMetadataContext.GetContext();
    UserAccount account = new UserAccount
    {
        emplid = input1.emplid,
        sso = input1.sso,
        deptid = input1.deptid,
        usertype = input1.usertype,
        status = input1.status,
        username = input1.username
    };

    Db.UserAccounts.Add(account);
    Db.SaveChanges();

    Dictionary<string, string> dict = new Dictionary<string, string>();
    dict.Add("status", "0");
    dict.Add("message", "User Addition Successful");

    Context.Response.Write(JsonConvert.SerializeObject(dict));
}
catch (System.Data.Entity.Infrastructure.DbUpdateException dbev)
{
    Dictionary<string, string> dict = new Dictionary<string, string>();
    dict.Add("status", "1");
    dict.Add("message", "User Addition Failed - User Already Exists");

    Context.Response.Write(JsonConvert.SerializeObject(dict));
}

您可以使用捕获所有异常,但如果您希望以不同方式处理特定异常,则单独处理它们可能会很有用。在您的示例中,您要添加到字典中,然后字典可以提供一些有用的反馈而不是崩溃。您将无法对所有块执行此操作。

我使用过的一些代码中的示例:

catch (System.Runtime.InteropServices.COMException comException)
{
    // Logout has already occurred
    this.VerboseLog($"Disconnect not required. ERROR LOGGED BUT WILL BE IGNORED; {comException}");
}
catch (Exception ex)
{
   this.ErrorLog(ex);
   throw;
}

在这第一个catch错误并不是真正的问题;它正在被记录,但它可以继续 运行。在第二个捕获中,错误是一个正在写入日志的问题,但不会进一步处理,因为我们不知道它是什么或如何处理它。

What is the advantage of specific Exception types and their use in multiple catch blocks?

问同一个问题的更好方法是 "what is a disadvantage of catching less specific Exception types." 这个问题的答案非常简单:您可能会无意中捕捉到您不知道如何处理的异常。

通常,代码只有在知道如何处理异常时才应该捕获异常,例如报告错误,使用计数器重试,要求最终用户决定如何继续,等等。仅当您将捕获的异常限制为特定组时才有可能,例如 DbUpdateException.

捕获特定异常的一个很好的 "bonus" 是您可以访问仅在特定子类上定义的属性和方法。例如,DbUpdateException 告诉您哪些条目未能通过 Entries 属性 保存,这让您有机会尝试重试。

最后,某些异常只能在程序的顶层捕获。这些异常表示编程错误 - 例如,访问 null 引用、访问数组末尾或负索引处的数组、除以零等。您的程序无法从这些错误中恢复,因为修复它们需要更改代码。因此,程序唯一可以做的就是在退出或启动重启序列之前记录或报告异常。

没有什么可以阻止您捕获异常,但不建议您这样做,除非您只想简单地记录异常并重新抛出它。

捕捉特定的异常可以让您处理您知道如何修复的特定场景。

这里有一些关于异常、它们的行为方式以及如何最好地处理它们的非常好的信息 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/