我知道如何使用try-catch-finally。然而,我不理解使用finally
的优势,因为我总是可以将代码放在try-catch块之后。
有清晰的示例吗?
finally
的好处,因为我可以把代码放在try-catch块之后。是否有明显的例子呢?你需要一个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
fs.Write()
抛出异常,我的fs.Close()
将会运行。这就是try/finally的全部意义所在。按照你的建议,文件将保持打开状态。 - H H它几乎总是用于清理,通常是通过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
块。
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
。
即使以下情况发生,finally
中的代码仍将执行:
try
块或catch
块中有return
语句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();
}
}
finally
成功地确保清理工作,而开发人员(比如我)可能无法确保清理工作。在下面的代码中,考虑抛出一个除SpecificException
以外的异常的情况。然后第一个示例仍将执行清理工作,而第二个示例则不会,尽管开发人员可能会认为“我捕获了异常并处理了它,所以肯定会运行后续代码。”
每个人都给出了使用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
示例是在catch
块中重新抛出异常(使用throw
,而不是throw ex
——但这是另一个话题),因此finally
是必要的,否则try
/catch
后面的代码将不会运行。通常情况下,这可以通过对IDisposable
资源使用using
语句来实现,但并非总是如此。有时清理工作不仅仅是调用Dispose
方法。
你不一定要用它来处理异常。你可以使用try/finally
在块中的每个return
之前执行一些清理工作。
无论是否发生错误,finally块始终会被执行。通常用于清理目的。
对于您的问题,Catch的一般用途是将错误抛回给调用者,在这种情况下,代码仍然会最终执行。
如果在 catch 块中发生异常(或重新抛出异常),则 catch 后面的代码将不会被执行 - 相反,finally 中的代码仍将被执行。
此外,即使使用 return 退出方法,finally 中的代码也会被执行。
当处理需要关闭的外部资源(如文件)时,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
}
try
{
this.Enabled = false;
// some process
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
this.Enabled = true;
}
无论异常是否在catch块中被重新抛出,finally块始终会被执行。
finally
;如果catch块没有捕获异常或重新抛出它,程序不会执行到finally块。 - Ani