使用“ try-finally”块而不包含“ catch”块


Answers:


118

您将使用它来确保在 try内容之后或在异常上发生,但是当您不希望使用该异常时。

只是要清楚,这不会隐藏异常。的finally在异常传播到调用堆栈之前运行块。

当您使用using关键字时,您也会无意中使用它,因为它会编译为try-finally(不是精确的转换,但出于参数的考虑,它已经足够接近了)。

try
{
    TrySomeCodeThatMightException();
}
finally
{
    CleanupEvenOnFailure();
}

finally不能保证在其中运行的代码能够运行,但是不能保证运行的代码是相当边缘的-我什至不记得了。我只记得,如果是那样的话,不运行finally不是您最大的问题的机会非常大:-)因此,基本上不要流汗。

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

从Paddy更新: 最终无法在.net try..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();
}

14
@AnthonyBlake异常未隐藏。如果发生异常,它将运行finally,然后将异常传播回调用堆栈。
亚当·霍兹沃思

2
对于边缘情况,如果进程被终止(例如,任务管理器中带有“终止进程”或由于断电),则最终将不会运行。
纳芬2012年

1
这里更多信息有关时,finally语句,将不会触发-不只是当进程被终止:stackoverflow.com/questions/111597/...
水稻

1
并非所有的finally都将运行的另一种明显情况是,如果在finally块中间发生错误。
Ben Hocking '02

2
最后,在我能想到的三种情况下,将不会调用它:终止进程,堆栈溢出和内存不足。所有这些基本上都会在遇到的确切时间停止程序的执行,并向OS发送信号以终止进程。
KeithS 2012年

5

using等价的try-finally。仅try-finally当您想要对内部进行一些清理finally并且不关心异常时,才使用。

最好的办法将是

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

这样做即使被调用using失败,代码也不会失败。

在某些情况下finally将不被执行。

  • 如果有StackOverflowExceptionExecutingEngineException
  • 进程从外部来源中被杀死。

希望这能回答您的疑问。


3

例如,如果您拥有在try块中创建和使用的非托管资源,则可以使用finally块来确保释放该资源。无论try块中发生了什么(例如异常),都将始终执行finally块。

例如,lock(x)语句实际上是:

System.Threading.Monitor.Enter(x); 
try { ... } 
finally 
{ 
    System.Threading.Monitor.Exit(x); 
} 

将始终调用finally块以确保释放互斥锁。


3

使用代码的良好解释:

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?尝试+不带+抓住+但是+带+最后+ doesn + t + throw + error +为什么+不+语法+ error +


2
这个“清理”的一个例子可能是saveLogFile(),无论如何我经常想把它放在程序的最后。
Vincent

1

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

另请参阅try-finally


1

尝试/最终:当您不想处理任何异常但想要确保某些操作发生时,无论被调用的代码是否引发异常。


1

我对C#一无所知,但似乎可以尝试一切,最终可以更优雅地使用using语句。C ++甚至没有RAII的最终结果


不必要。如果您想运行一些简单处理无法处理的自定义代码,该怎么办。例如,如果您在中增加计数器try,然后在中减少计数器,则finally不能在using语句中这样做。
Mark A. Donohoe

@ MarkA.Donohoe您是否可以创建一个对象,该对象包含对计数器的引用,该引用在处理后会递减?
尼尔·G

是的,但是为什么要创建整个对象只是为了实现与using语句一起使用的一次性接口?这使问题适合解决方案。ATry-[Catch]-Finally无需创建此类对象即可处理所有这些。
Mark A. Donohoe

@ MarkA.Donohoe对象解决方案是优越的,因为它在一个地方实现了包围模式。您不能忘记,放错地方或意外删除减量代码。
尼尔·G

对不起,我不同意。您正在关注显式递减行为,但是谁说它们必须完全匹配?如果还有其他递增/递减逻辑也依赖于函数中的其他成员怎么办?另外,您现在不仅要引入一个仅用于一种用途的新对象,而且还要在堆上而不是堆栈上的简单int这样做。肯定有一个时间和一个地方可以使用,using但是您不能像您一样发表一揽子声明。同样,那是通过解决方案定义问题,对我而言,这是倒退的。
Mark A. Donohoe

1

在这种情况下,您可能希望最终使用try:通常使用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

这是我经常使用的用例:

int? x; //note the nullable type here!
try
{
    x = int.Parse(someString);
}
catch { } //don't care, let it just be null

0

1.我们可以使用没有catch的try块,但我们应该使用catch / finally,其中的任何一个。2.我们不能只使用try块。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.