哪里需要finally?

发布于 2024-10-17 06:11:13 字数 107 浏览 2 评论 0原文

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

I know how to use try-catch-finally. However I do not get the advance of using finally as I always can place the code after the try-catch block.
Is there any clear example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

最佳男配角 2024-10-24 06:11:13

它几乎总是用于清理,通常通过 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 块。

It's almost always used for cleanup, usually implicitly via a using statement:

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

Now this is not equivalent to

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

because the "read some stuff" code could throw an exception or possibly return - and however it completes, we want to dispose of the stream.

So finally blocks are usually for resource cleanup of some kind. However, in C# they're usually implicit via a using statement:

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

finally blocks are much more common in Java than in C#, precisely because of the using statement. I very rarely write my own finally blocks in C#.

り繁华旳梦境 2024-10-24 06:11:13

您需要一个finally,因为您不应该总是有一个catch:

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

You need a finally because you should not always have a catch:

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

The above method does not catch errors from using fs, leaving them to the caller. But it should always close the stream.

Note that this kind of code would normally use a using() {} block but that is just shorthand for a try/finally. To be complete:

    using(var fs = new FileStream(...))
    {
       fs.Write(...);
    } // invisible finally here
怪我入戏太深 2024-10-24 06:11:13
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

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

When you have a finally block, the code therein is guaranteed to run upon exit of the try. If you place code outside of the try/catch, that is not the case. A more common example is the one utilized with disposable resources when you use the using statement.

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

expands to

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

This ensures that all unmanaged resources get disposed and released, even in the case of an exception during the try.

*Note that there are situations when control does not exit the try, and the finally would not actually run. As an easy example, PowerFailureException.

空心↖ 2024-10-24 06:11:13

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


每个人都给出了使用 try/finally 的理由,没有 catch。即使您抛出异常,使用 catch 来执行此操作仍然有意义。考虑您想要返回值的情况*。

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

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

bool success;

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

DoImportantCleanup();
return success;

*我确实认为更好的例子try/catch/finally 是重新抛出异常的时候(使用thrownot< /em> throw ex - 但这是另一个主题)在 catch 块中,因此 finally 是必要的,因为在 之后没有代码code>try/catch 将不会运行。这通常是通过对 IDisposable 资源使用 using 语句来完成的,但情况并非总是如此。有时,清理并不是专门的 Dispose 调用(或者不仅仅是 Dispose 调用)。

Update: This is actually not a great answer. On the other hand, maybe it is a good answer because it illustrates a perfect example of finally succeeding where a developer (i.e., me) might fail to ensure cleanup properly. In the below code, consider the scenario where an exception other than SpecificException is thrown. Then the first example will still perform cleanup, while the second will not, even though the developer may think "I caught the exception and handled it, so surely the subsequent code will run."


Everybody's giving reasons to use try/finally without a catch. It can still make sense to do so with a catch, even if you're throwing an exception. Consider the case* where you want to return a value.

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

The alternative to the above without a finally is (in my opinion) somewhat less readable:

bool success;

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

DoImportantCleanup();
return success;

*I do think a better example of try/catch/finally is when the exception is re-thrown (using throw, not throw ex—but that's another topic) in the catch block, and so the finally is necessary as without it code after the try/catch would not run. This is typically accomplished with a using statement on an IDisposable resource, but that's not always the case. Sometimes the cleanup is not specifically a Dispose call (or is more than just a Dispose call).

皓月长歌 2024-10-24 06:11:13

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

  • trycatch 块中有 return 语句
    OR
  • 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();
  }
}

The code put in the finally block is executed even when:

  • there are return statements in the try or catch block
    OR
  • the catch block rethrows the exception

Example:

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();
  }
}
梦亿 2024-10-24 06:11:13

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

you don't necessarily use it with exceptions. You may have try/finally to execute some clean up before every return in the block.

下雨或天晴 2024-10-24 06:11:13

无论是否出现错误,finally 块都会被执行。它通常用于清洁目的。

对于您的问题, Catch 的一般用途是将错误返回给调用者,在这种情况下代码最终仍然执行。

The finally block always is executed irrespective of error obtained or not. It is generally used for cleaning up purposes.

For your question, the general use of Catch is to throw the error back to caller, in such cases the code is finally still executes.

不交电费瞎发啥光 2024-10-24 06:11:13

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

The finally block will always be executed even if the exception is re-thrown in the catch block.

你的心境我的脸 2024-10-24 06:11:13

如果 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

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

If an exception occurs (or is rethrown) in the catch-block, the code after the catch won't be executed - in contrast, code inside a finally will still be executed.

In addition, code inside a finally is even executed when the method is exited using return.

Finally is especially handy when dealing with external resources like files which need to be closed:

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

Note however, that in this example you could also use using:

using (Stream file = File.Open(/**/))
{
  //Code
}
掀纱窥君容 2024-10-24 06:11:13

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

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

For example, during the process you may disable WinForm...

try
{
this.Enabled = false;
// some process
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
this.Enabled = true;
}
无戏配角 2024-10-24 06:11:13

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

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

I am not sure how it is done in c#, but in Delphi, you will find "finally" very often. The keyword is manual memory management.

MyObject := TMyObject.Create(); //Constructor
try 
     //do something
finally
    MyObject.Free(); 
end;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文