try {..} catch {...}与最终和没有它之间的区别

时间:2013-11-05 22:00:19

标签: c# try-catch try-catch-finally

这样的代码有什么区别:

string path = @"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}

finally
{
    if (file != null)
    {
        file.Close();
    }
}

和此:

string path = @"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
if (file != null)
{
    file.Close();
}

在这个结构中真的最终是必要的。微软为何提供此类构建?这似乎是多余的。不是吗?

5 个答案:

答案 0 :(得分:9)

想象一下,如果发生了其他未处理的异常,例如一个ArgumentOutOfRangeException,或者如果你想重新抛出异常或从catch块抛出一个包装的异常:

  1. 无论是否发生异常,第一个块都会确保文件已关闭。

  2. 如果没有发生异常或发生IOException,则第二个块关闭文件。它不处理任何其他情况。

答案 1 :(得分:6)

即使存在未捕获的异常,第一个块也将关闭该文件。

仅当没有异常或者捕获到任何抛出的异常时,第二个块才会关闭文件。

如果trybreakgotoreturncontinue或任何其他跳转,第一个也会确保该文件已关闭构造会导致执行移出try块之外。第二个没有,因此可能导致资源未被关闭。

答案 2 :(得分:2)

在您的示例中,如果您的代码抛出System.IO.IOException以外的异常,则无法保证您的清理代码能够运行。使用finally块,无论抛出什么类型的异常,其中的代码都将运行。

答案 3 :(得分:0)

想象一下catch{}内部有一个异常,最终内部的代码仍会运行,但if (file != null){}阻止不会。

答案 4 :(得分:0)

在这种情况下,它是多余的。

如果您例如重新抛出异常并且仍希望在块之后运行某些代码,那么它是有用的:

try {
  // do something dangerous
} catch(...) {
  // log the error or something
  throw; // let the exception bubble up to the caller
} finally {
  // this always runs
}
// this only runs if there was no exception

另一个例子是如果catch可能由于其他原因而抛出异常:

try {
  // do something dangerous
} catch(...) {
  // handle the error
  // log the error, which may cause a different exception
} finally {
  // this runs even if the catch crashed
}
// this only runs if there was no exception, or the code in the catch worked

简单地说,由于代码可能因为您可能甚至不知道的许多原因而崩溃,因此将清理放在finally块中以确保它运行无论发生什么都是有用的。