哪里最后是必要的?

时间:2011-02-11 13:16:28

标签: c# exception finally

我知道如何使用try-catch-finally。但是我没有得到使用finally的进展,因为我总是可以将代码放在try-catch块之后。 有没有明确的例子?

11 个答案:

答案 0 :(得分:4)

你需要一个终极因为你不应该总是有一个问题:

void M()
{
    var fs = new FileStream(...);
    try
    {
       fs.Write(...);
    }
    finally
    {
       fs.Close();
    }
}

上述方法没有捕获使用fs的错误,将它们留给调用者。但它应该总是关闭流。

请注意,这种代码通常会使用using() {}块,但这只是try / finally的简写。完成:

    using(var fs = new FileStream(...))
    {
       fs.Write(...);
    } // invisible finally here

答案 1 :(得分:4)

它几乎总是用于清理,通常隐含地通过using语句:

FileStream stream = new FileStream(...);
try
{
    // Read some stuff
}
finally
{
    stream.Dispose();
}

现在这 等同于

FileStream stream = new FileStream(...);
// Read some stuff
stream.Dispose();

因为“读取一些东西”代码可能抛出异常或可能返回 - 但是它完成后,我们想要处理流。

所以finally块通常用于某种资源清理。但是,在C#中,它们通常是通过using语句隐含的:

using (FileStream stream = new FileStream(...))
{
    // Read some stuff
} // Dispose called automatically

finally块在Java中比在C#中更常见,正是因为using语句。我很少在C#中编写自己的finally块。

答案 2 :(得分:3)

try 
{
    DoSomethingImportant();
}
finally
{
    ItIsRidiculouslyImportantThatThisRuns();
}

当你有一个finally块时,其中的代码保证在try退出时运行。如果将代码放在try / catch之外,则情况并非如此。一个更常见的例子是当您使用using语句时使用的一次性资源。

using (StreamReader reader = new StreamReader(filename))
{
}

扩展为

StreamReader reader = null;
try
{
    reader = new StreamReader(filename);
    // do work
}
finally 
{
    if (reader != null)
       ((IDisposable)reader).Dispose();
}

这确保即使在try期间发生异常的情况下也会处置和释放所有非托管资源。

*请注意,有些情况下控件不会退出try,并且finally实际上不会运行。举个简单的例子,PowerFailureException

答案 3 :(得分:2)

即使在以下情况下,finally块中的代码也会被执行:

  • returntry块中有catch个语句
  • catch块重新抛出异常

示例:

public int Foo()
{
  try
  {
    MethodThatCausesException();
  }
  catch
  {
    return 0;
  }

  // this will NOT be executed
  ReleaseResources();
}

public int Bar()
{
  try
  {
    MethodThatCausesException();
  }
  catch
  {
    return 0;
  }
  finally
  {
    // this will be executed
    ReleaseResources();
  }
}

答案 4 :(得分:2)

更新:这实际上不是一个好的答案。另一方面,也许 是一个很好的答案,因为它说明了finally成功的完美示例,其中开发人员(即我)可能无法确保正确清理。在下面的代码中,考虑抛出异常其他而不是SpecificException的情况。然后第一个例子仍将执行清理,而第二个例子仍然不会,即使开发人员可能认为“我抓住了异常并处理了它,所以后续代码肯定会运行。”


每个人都有理由在没有 try的情况下使用finally / catch 。使用一个catch 仍然有意义,即使您正在抛出异常。考虑要返回值的情况*。

try
{
    DoSomethingTricky();
    return true;
}
catch (SpecificException ex)
{
    LogException(ex);
    return false;
}
finally
{
    DoImportantCleanup();
}

上述没有 a finally的替代方案(在我看来)可读性较差:

bool success;

try
{
    DoSomethingTricky();
    success = true;
}
catch (SpecificException ex)
{
    LogException(ex);
    success = false;
}

DoImportantCleanup();
return success;

*我确实认为try / catch / finally更好示例是在重新抛出异常时(使用{{在throw块中,1}},不是 throw ex - 但这是另一个主题,因此catch是必要的,因为finally没有代码try 1}} / catch无法运行。这通常通过using资源上的IDisposable语句来完成,但情况并非总是如此。有时,清理不是专门的Dispose电话(或只是Dispose电话)。

答案 5 :(得分:1)

您不一定会将其用于例外情况。您可能需要try/finally在块中的每个return之前执行一些清理。

答案 6 :(得分:1)

无论是否获得错误,都始终执行finally块。它通常用于清理目的。

对于你的问题,Catch的一般用法是将错误抛回调用者,在这种情况下,代码最终仍会执行。

答案 7 :(得分:0)

即使在catch块中重新抛出异常,也会始终执行finally块。

答案 8 :(得分:0)

我不确定它是如何在c#中完成的,但在Delphi中,你会经常发现“终于”。关键字是手动内存管理。

MyObject := TMyObject.Create(); //Constructor
try 
     //do something
finally
    MyObject.Free(); 
end;

答案 9 :(得分:0)

如果catch块中发生异常(或重新抛出),catch之后的代码将不会被执行 - 相反,finally中的代码仍将被执行。

此外,当使用return退出方法时,甚至会执行finally中的代码。

最后在处理需要关闭的文件等外部资源时非常方便:

Stream file;
try
{
  file = File.Open(/**/);
  //...
  if (someCondition)
     return;
  //...
}
catch (Exception ex)
{
   //Notify the user
}
finally
{
  if (file != null)
    file.Close();
}

但请注意,在此示例中,您还可以使用使用

using (Stream file = File.Open(/**/))
{
  //Code
}

答案 10 :(得分:0)

例如,在此过程中您可以禁用WinForm ...

try
{
this.Enabled = false;
// some process
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
this.Enabled = true;
}