在不使用'catch'块的情况下使用'try-finally'块

113

在IT技术中是否存在适合使用try-finally块而不带catch块的情况?


2
在 MSDN 上,查看 try-finally (C# Reference)。请注意,该文章将 tryfinally 的组合使用称为 "try-finally 语句。" - DavidRR
10个回答

175
你可以使用 finally 块来确保在 try 代码段执行后或者出现异常时,执行一些操作但不消耗该异常。 需要明确的是,这并不会隐藏异常。在异常被传播到调用栈之前,finally 块会先执行。 当你使用 using 关键字时,也会无意中使用它,因为这将编译为一个 try-finally 代码块(虽然不是完全相同的转换,但是近似地说它足够接近)。
try
{
    TrySomeCodeThatMightException();
}
finally
{
    CleanupEvenOnFailure();
}

finally 中的代码并不保证一定会运行。但是在它不能保证运行的情况下,这种情况是相当少见的——我甚至都记不起来了。我只记得,如果你遇到这种情况,那么你最大的问题很可能不是不运行 finally :-) 所以基本上不要太担心。

Tobias 的更新:如果进程被终止,则 finally 不会运行。

Paddy 的更新:.net try..finally 块中 finally 不执行的条件

最常见的例子就是在数据库连接或外部资源释放时,即使代码失败也要执行 finally 以确保资源被正确释放:

using (var conn = new SqlConnection("")) // Ignore the fact we likely use ORM ;-)
{
    // Do stuff.
}

编译后会生成类似于某些内容的东西:

SqlConnection conn;

try
{
    conn = new SqlConnection("");
    // Do stuff.
}
finally
{
    if (conn != null)
        conn.Dispose();
}

21
异常并没有被隐藏。如果发生了异常,它会运行 finally 语句并将异常沿着调用栈向上传递。 - Adam Houldsworth
2
至于边缘情况,如果进程被终止(例如在任务管理器中选择“终止进程”或因为停电等原因),finally块将不会执行。 - Nuffin
1
这里有更多关于 finally 语句不会触发的信息 - 不仅仅是当进程被终止时:https://dev59.com/mnVD5IYBdhLWcg3wBm5h - Paddy
1
另一个明显的情况是,如果在 finally 块中间发生错误,则不会运行其中的 所有 代码。 - Ben Hocking
4
我会尽力为您翻译:最终,程序不会在三种情况下被调用:杀死进程、堆栈溢出和内存耗尽。所有这些情况基本上都会在遇到它们的确切点停止程序执行,并向操作系统发出终止该进程的信号。 - KeithS
显示剩余3条评论

9

代码演示的好解释:

void MyMethod1()
{
    try
    {
        MyMethod2();
        MyMethod3();
    }
    catch(Exception e)
    {
        //do something with the exception
    }
}


void MyMethod2()
{
    try
    {
        //perform actions that need cleaning up
    }
    finally
    {
        //clean up
    }
}


void MyMethod3()
{
    //do something
}

如果MyMethod2或者MyMethod3抛出了异常,它将被MyMethod1捕获。但是,在异常传递到MyMethod1之前,MyMethod2中的代码需要运行清理代码,例如关闭数据库连接。

http://forums.asp.net/t/1092267.aspx?Try+without+Catch+but+with+finally+doesn+t+throw+error+Why+no+syntax+error+

2
一个“清理”操作的例子是saveLogFile(),我经常希望无论如何都将其放在程序的最后。 - Vincent

5

using 相当于 try-finally。只有在你想要在 finally 中进行一些清理工作并且不关心异常时,才会使用 try-finally

最佳方法

try
{
   using(resource)
   {
       //Do something here
   }   
}catch(Exception)
{
     //Handle Error
}

即使被称为 using 的清理操作失败,您的代码也不会失败。

在某些情况下,finally 不会执行。

  • 如果出现任何 StackOverflowExceptionExecutingEngineException
  • 进程被外部来源终止。

4
如果你在try块中创建并使用了一个未经管理的资源,你可以使用finally块来确保释放该资源。无论try块中发生什么(例如异常),finally块都将被执行。
例如,lock(x)语句实际上是:
System.Threading.Monitor.Enter(x); 
try { ... } 
finally 
{ 
    System.Threading.Monitor.Exit(x); 
} 

finally块将始终被调用以确保独占锁被释放。


1

当您无论捕获哪些(如果有)异常或者即使没有捕获异常也想要在块退出之前执行一些代码时,需要使用 finally 块。例如,您可能希望关闭一个打开的文件。

另请参阅 try-finally


1

try/finally:当您不想处理任何异常但希望确保某些操作发生,无论被调用代码是否抛出异常时使用。


1
这里有一个可能需要使用try finally的情况:当你通常会使用using语句,但由于通过反射调用方法而无法使用时。
这样做是行不通的。
using (objMsg  =  Activator.CreateInstance(TypeAssist.GetTypeFromTypeName("omApp.MessagingBO")))
{

}

而应使用

           object objMsg = null;
            try
            {
                objMsg
                   = Activator.CreateInstance(TypeAssist.GetTypeFromTypeName("myAssembly.objBO"));

                strResponse = (string)objMsg.GetType().InvokeMember("MyMethod", BindingFlags.Public
                        | BindingFlags.Instance | BindingFlags.InvokeMethod, null, objMsg,
                        new object[] { vxmlRequest.OuterXml });
            }               
            finally
            {
                if (objMsg!=null)
                    ((IDisposable)objMsg).Dispose();
            }

0

1.我们可以使用try块而不必要catch,但我们必须使用catch/finally这两者之一。 2.我们不能单独使用try块。


0

0

我对C#一无所知,但似乎你可以用using语句更优雅地完成try-finally的所有操作。由于RAII的结果, C++甚至没有finally。


1
不一定。如果您想运行一些不被简单处理的自定义代码,怎么办呢?例如,如果您在 try 中增加一个计数器,然后在 finally 中减少它,您无法在 using 语句中执行此操作。 - Mark A. Donohoe
@MarkA.Donohoe,您能否创建一个对象来持有对计数器的引用,在该对象被处理时将其递减? - Neil G
是的,但为什么要创建一个完整的对象来实现可处理接口以与使用语句一起使用呢?这是将问题适应解决方案。Try-[Catch]-Finally可以处理所有这些,而无需创建这样的对象。 - Mark A. Donohoe
@MarkA.Donohoe 对象解决方案更优越,因为它在一个地方实现了括号模式。您不能忘记、放错位置或意外删除减量代码。 - Neil G
对不起,但我不同意。你关注的是显式递减行为,但谁说它们必须完全匹配呢?如果还有其他增量/减量逻辑也依赖于函数中的其他成员怎么办?此外,你现在不仅为一个用途引入了一个新对象,而且还在堆上这样做,而不是在栈上使用简单的int。使用using肯定有时机和地点,但你不能像你所说的那样做出笼统的陈述。再次强调,这是通过解决方案来定义问题,对我来说是相反的。 - Mark A. Donohoe
显示剩余6条评论

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