try-catch-finally的用例同时包含catch和finally

Hei*_*nzi 8 c# java language-agnostic vb.net try-catch-finally

我理解try-catch如何工作以及try-finally如何工作,但我发现自己在两个完全不同的场景中使用它们(通常):

  • try-finally(或using在C#和VB中)主要用于某些中型代码块,它使用一些需要正确处理的资源.
  • try-catch主要用于
    • 围绕一个单一的陈述,可以以一种非常具体的方式或失败
    • (作为一个包罗万象的)在应用程序的非常高级别,通常直接在一些用户界面操作下面.

根据我的经验,try-catch-finally最合适的情况,即我想要捕获某个特定异常的块与我使用某些可处理资源的块完全相同,这种情况极为罕见.然而,C#,VBJava的语言设计者似乎认为这是一个非常常见的场景; VB的设计师甚至考虑增加捕捉using.

我错过了什么吗?或者我是否因为限制性地使用try-catch而过于迂腐?


编辑:澄清:我的代码通常看起来像这样(为清晰起见,函数展开):

Try
    do something
    Aquire Resource (e.g. get DB connection)
    Try 
        do something
        Try
            do something that can fail
        Catch SomeException
            handle expected error
        do something else... 
    Finally 
        Close Resource (e.g. close DB connection)
    do something
Catch all
    handle unexpected errors
Run Code Online (Sandbox Code Playgroud)

这似乎比将两个捕获中的任何一个放在同一水平上更有意义,最后只是为了避免缩进.

Fil*_*erg 16

来自MSDN的引用

catch的常见用法最后是在try块中获取和使用资源,处理catch块中的异常情况,并释放finally块中的资源.

所以为了使它更清晰,想想你要运行的代码,在99%的情况下它运行得很好但是在块中的某个地方可能会出现错误,你不知道创建的资源在哪里和昂贵.

为了100%确定资源被处理掉,你使用finally块,但是,你想要指出发生错误的1%的情况,因此你可能想要设置登录的问题 - 荷兰国际集团截面.

这是一种非常常见的情况.

编辑 - 一个实际的例子

这里有一些很好的例子:带有SqlTransaction类的SQL事务.这只是使用Try,Catch和Finally的众多方法之一,它很好地展示了它,尽管using(var x = new SqlTranscation)有时可能会有效.

所以这里.

var connection = new SqlConnection();

var command = new SqlCommand();

var transaction = connection.BeginTransaction();

command.Connection = connection;
command.Transaction = transaction;
Run Code Online (Sandbox Code Playgroud)

这里有更有趣的部分

///
/// Try to drop a database
///
try
{
    connection.Open();

    command.CommandText = "drop database Nothwind";

    command.ExecuteNonQuery();
}
Run Code Online (Sandbox Code Playgroud)

因此,让我们假设上述因某些原因而失败,并抛出异常

///
/// Due to insufficient priviligies we couldn't do it, an exception was thrown
///
catch(Exception ex)
{
    transaction.Rollback();
}
Run Code Online (Sandbox Code Playgroud)

该交易将被回滚!请记住,您对try/catch中的对象所做的更改将不会回滚,即使您将其嵌入使用中也是如此!

///
/// Clean up the resources
///
finally
{

    connection.Close();
    transaction = null;
    command = null;
    connection = null;
}
Run Code Online (Sandbox Code Playgroud)

现在资源被清理干净了!


Eri*_*ert 12

不是你问题的答案,而是一个有趣的事实.

C#编译器的Microsoft实现实际上无法处理try-catch-finally.当我们解析代码时

try { Foo() } 
catch(Exception e) { Bar(e); }
finally { Blah(); }
Run Code Online (Sandbox Code Playgroud)

我们实际上假装代码是写的

try 
{
   try { Foo(); }
   catch(Exception e) { Bar(e); }
}
finally { Blah(); }
Run Code Online (Sandbox Code Playgroud)

这样编译器的其余部分 - 语义分析器,可达性检查器,代码生成器等 - 只需要处理try-catch和try-finally,永远不要尝试catch-finally.在我看来,这是一个愚蠢的早期转型,但它确实有效.

  • 好吧,如果它们*在逻辑上不相同,那么对我们进行转换是不合适的,所以我们不会这样做.由于它们*在逻辑上是相同的,我们可以逃脱这个偷偷摸摸的伎俩. (2认同)

p.m*_*ino 10

例:

Try
   Get DB connection from pool
   Insert value in table
   do something else...
Catch
   I have an error... e.g.: table already contained the row I was adding
   or maybe I couldn't get the Connection at all???
Finally
   if DB connection is not null, close it.
Run Code Online (Sandbox Code Playgroud)

你无法真正得到一个更"普通"的例子.遗憾的是,有些人仍然忘记将最后的连接放在最后,它所属的地方,而不是在Try块...... :(


Ste*_*n C 6

经常编写如下代码:

Handle h = ...
try {
   // lots of statements that use handle
} catch (SomeException ex) {
   // report exception, wrap it in another one, etc
} catch (SomeOtherException ex) {
   // ...
} finally {
   h.close();
}
Run Code Online (Sandbox Code Playgroud)

所以也许你只是过于迂腐...例如,通过尝试/捕捉个别陈述.(有时候这是必要的,但根据我的经验,你通常不需要那么精细.)