假设你有一个 TRY 块。我尝试写入文件,但该文件不存在,因此引发异常。
try
{
TryWritingToFile();
}
catch (Exception)
{
CreateFile();
//now I want to go back and try to write to the file again.
}
如何回到 try 块的开头?我需要在 catch 块中“重试”吗?这不是重复代码吗?
假设你有一个 TRY 块。我尝试写入文件,但该文件不存在,因此引发异常。
try
{
TryWritingToFile();
}
catch (Exception)
{
CreateFile();
//now I want to go back and try to write to the file again.
}
如何回到 try 块的开头?我需要在 catch 块中“重试”吗?这不是重复代码吗?
bool ok = false;
while(!ok)
{
try
{
TryWritingToFile();
ok = true;
}
catch (Exception)
{
CreateFile();
//now I want to go back and try to write to the file again.
}
}
如何回到 try 块的开头?
你不能,但你可以再次调用相同的函数——递归。
请注意,捕获全局Exception
异常并不是最佳实践。
对于从发生异常的确切点重试操作的一般情况,您需要一个异常过滤器,.NET 支持,但 C# 不支持。使用 VB.NET、F# 或 C++/CLI。或者也许是 MSIL。
而且我不太确定EXCEPTION_CONTINUE_EXECUTION
在异常过滤器表达式中返回的 .NET 等价物是什么。
这必须在异常过滤器中完成的原因是异常过滤器是在第一次机会异常处理期间评估的,而调用堆栈仍然完好无损。在第二次机会异常处理期间执行 catch 块时,堆栈展开已经开始,并且无法恢复不再在调用堆栈上的调用帧的执行。
在这里捕获一些特定的文件 I/O 异常可能比基类 Exception 更好。
为什么不将整个代码块包装在一个while循环中,检查成功设置的某种布尔值?
您可以使用任意数量的复杂技巧来实现这种效果,例如:
bool success = false;
while(!success)
{
try
{
WriteToFile();
success = true;
}
catch()
{
CreateFile();
}
}
但它们都是有问题的,应该不惜一切代价避免。控制流不那么明显,而且通常还有其他缺点。例如,上面的代码是无限循环的好方法。
在这种情况下,问题的根源通常是您将异常用作控制流机制。例如,在这里您依靠异常来告诉您文件是否存在。这是有问题的,因为异常会破坏控制流并带来性能损失。更好的选择是重新排列代码,以便您不依赖异常来传达除异常情况之外的任何内容。几乎总是有一种更直接(和更有效)的方法来找出异常告诉你什么。
例如:
if(!CheckFileExists()) CreateFile();
WriteToFile();