何时使用和何时不使用Try Catch Finally

12

我正在使用 .net 3.5 创建 asp.net 网络应用程序,想知道何时使用 Try Catch Finally 块,何时不使用?尤其是,大部分的 try catch 都包裹在执行存储过程和填充文本字段或网格视图方面。您会在执行存储过程和填充数据显示控件时每次都使用 Try Catch 吗?

我的代码块通常如下所示:

    protected void AddNewRecord()
    {
        try
        {
           //execute stored proc
           // populate grid view controls or textboxes
        }
        catch (Exception ex)
        {
           //display a messagebox to user that an error has occured
           //return
        }
        finally
        { }
   }

请参见此链接:https://dev59.com/4HRB5IYBdhLWcg3wz6QK。 - 0x49D1
请查阅J. Richter所著的《CLR via C#》第三版。该书详细介绍了异常处理概念,是一个非常好的参考资料。 - ileon
7个回答

11
答案是“这取决于具体情况”。
你可能想在每个原子操作周围使用try{...} catch {...},以便如果出现问题,可以回滚到上一个良好状态(使用事务)。这可能是一个或多个存储过程 - 这取决于您的应用程序。
如果您捕获异常,请确保明确指定要捕获哪些异常。您不应该有catch (Exception ex)catch() - 被称为“catch all”异常处理 - 而应该有特定的catch语句,例如catch (IndexOutOfRangeException ex)。
但是,如果您无法处理异常或者没有任何方法来清理异常,那么您就不应该捕获它。

“原子”操作是什么意思? - user279521
3
“atomic”——类似于原子,因为它不能再分割。它可能包含多个步骤,但如果单独执行每个步骤是没有意义的。例如,如果你修复了代码中的一个错误,但这需要对多个类进行编辑,则所有文件的检入被称为原子的,因为只检入其中一个文件是没有意义的。 - ChrisF
1
@Chris S - 如果你要挑剔的话 ;) 它来自希腊语,ἄτομος(átomos),意思是不可切割/不可分割的。 - ChrisF

4

当你想在catch块中处理异常时,应该只使用try catch。我所说的“处理”是指记录错误、由于错误选择不同的路径等。如果你只是想重新抛出异常,那么使用try catch就没有意义。


1
如果你想记录错误,就没有必要在异常发生的地方捕获它--相反,你可以在代码退出点处设置一个catch,记录代码中任何地方发生的异常。 - Polyfun
你说得很有道理,但我认为这在很大程度上取决于应用程序的整体架构。实际上,我只是提供了一个可能需要使用try catch的示例。 - kemiller2002
如果一个对象的不变量依赖于块中的所有代码都执行,那该怎么办?在这种情况下,我认为应该通过一个块来保护代码,如果在对象的不变量可能不成立的时候发生异常,就明确地使对象无效。如果异常将导致调用代码放弃损坏的对象,则放弃损坏的对象的行为将解决问题。如果调用代码尝试使用损坏的对象,这样的尝试应该引发异常,从而强制进一步展开,直到事情得到解决或彻底死亡。 - supercat

1

正如其他人所说,这取决于情况。我倾向于在两种情况下使用try/catch/finally块:

  • 我需要以某种方式处理异常,而不仅仅是重新抛出它。

  • 我需要在finally块中清理一些资源。

除了这两种情况之外,我让调用代码处理可能发生的任何异常。


顺便提一下,using 基本上是用于清理资源(通过 Dispose)的 try-finally 块。 - Brian
@Brian - 正确,但并不是所有需要清理的东西都实现了IDisposable(或Dispose)。 - Justin Niessner

1
除了其他人所说的之外,一定要避免做这件事:
    try
    {
        throw new ApplicationException("Fake sql ex");
    }
    //catch and do nothing.  swallowing exceptions
    catch(Exception){ }                 

2
Pokemon异常处理:必须抓住它们! - Pierre-Alain Vigeant

0

大多数情况下,您不应该捕获异常。有些情况下,捕获异常是有意义的,例如:

当您可以从特定异常中恢复时。 当您需要记录或报告它(例如,向用户)-通常在代码的顶层。 当调用者无法处理异常时,因此您需要将其转换为其他错误格式。

此外,using块语句可用于实际调用IDisposable对象上的Dispose,这消除了try...finally的需要。


如果我想向用户显示一个消息框,内容为“加载数据时发生错误”,但又不想使用 Try Catch 块,我该如何实现? - user279521
你需要使用try-catch来弹出带有异常的消息框。 - Dan McClain
就像我之前所说的,你只需要在代码的顶层添加这个语句:“当你需要记录或报告它(例如向用户)时——通常在代码的顶层。” - Polyfun

0

你期望存储过程返回什么样的异常?如果你不使用pokemon exception handling,并且确切知道你的应用程序应该做什么,那么任何不符合你想要捕获的特定异常的内容都将被Application对象捕获。

换句话说,不要使用catch {}catch (Exception),而是使用专门的异常处理:

catch(SqlException e)
{
   // Log stacktrace and show a friendly error to your user
}

Application.Error事件是应该捕获意外行为并比简单让客户返回您说“我的字段没有显示任何内容”更易跟踪的地方。


没有特别的异常被期望,但是“为了安全起见”,过去有人告诉我所有数据库调用都应该包含在try catch块中。 - user279521
但是您不需要捕获异常。您可以愉快地捕获所有SqlExceptions或您正在使用的任何其他数据库。如果抛出其他异常,您可能希望知道它而不是悄悄地死去。 - Chris S

0
在最内层循环中使用“try catch”来保持当发生特定异常时继续执行。要注意的是,如果你有一个循环执行了10,000次,而在第十次重复上出现了异常,但不会影响其他9,990次循环,则捕获异常并让循环继续运行可能很有用。另一方面,如果异常指示11、12、13等循环次数也将失败,那么让异常终止循环比继续尝试无法工作的操作要快得多。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接