这样的代码有什么区别:
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();
}
在这个结构中真的最终是必要的。微软为何提供此类构建?这似乎是多余的。不是吗?
答案 0 :(得分:9)
想象一下,如果发生了其他未处理的异常,例如一个ArgumentOutOfRangeException
,或者如果你想重新抛出异常或从catch块抛出一个包装的异常:
无论是否发生异常,第一个块都会确保文件已关闭。
如果没有发生异常或发生IOException
,则第二个块仅关闭文件。它不处理任何其他情况。
答案 1 :(得分:6)
即使存在未捕获的异常,第一个块也将关闭该文件。
仅当没有异常或者捕获到任何抛出的异常时,第二个块才会关闭文件。
如果try
有break
,goto
,return
,continue
或任何其他跳转,第一个也会确保该文件已关闭构造会导致执行移出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
块中以确保它运行无论发生什么都是有用的。