我有一个try..catch块,看起来像这样:
try
{
...
}
catch (IOException ioEx)
{
...
}
catch (Exception ex)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我想处理某种IOException,即共享冲突(Win32 0x20).其他IOExceptions和所有其他Exception后代应该通过第二个catch-all catch来处理.
一旦我知道IOException不是共享冲突,我怎样才能将错误处理流程干净地重定向到一般catch?如果我在catch (IOException)第二次捕获中重新抛出则不会调用.我知道我可以嵌套try..catches但是有更清洁的方法吗?
在方法中考虑重复的代码肯定会起作用,但我注意到,一般来说,当你使用因式方法进行异常处理时,它往往会产生微妙的问题.
首先,一个catch子句可以在异常之前直接访问所有局部变量.但是当你将异常处理"外包"到另一种方法时,你必须将状态传递给它.当您更改代码时,处理程序方法的签名也会发生更改,这可能是更复杂方案中的可维护性问题.
另一个问题是程序流程可能会模糊不清.例如,如果处理程序方法最终重新抛出异常,那么像Resharper这样的C#编译器和代码分析器看不到它:
private void Foo()
{
string a = null;
try
{
a = Path.GetDirectoryName(a);
System.Diagnostics.Debug.Print(a);
}
catch (Exception ex)
{
HandleException(ex, a); //Note that we have to pass the "a"
System.Diagnostics.Debug.Print(
"We never get here and it's not obvious" +
"until you read and understand HandleException"
);
...!
}
}
static void HandleException(Exception ex, string a)
{
if (a != null)
System.Diagnostics.Debug.Print("[a] was not null");
throw (ex); //Rethrow so that the application-level handler catches and logs it
}
Run Code Online (Sandbox Code Playgroud)
VS
private void Bar()
{
string a = null;
try
{
a = System.IO.Path.GetDirectoryName(a);
System.Diagnostics.Debug.Print(a);
}
catch (Exception ex)
{
if (a != null)
System.Diagnostics.Debug.Print("[a] was not null");
throw; //Rethrow so that the application-level handler catches and logs it
System.Diagnostics.Debug.Print(
"We never get here also, but now " +
"it's obvious and the compiler complains"
);
...!
}
}
Run Code Online (Sandbox Code Playgroud)
如果我想避免这些(次要的)问题,那么似乎没有比嵌套try..catch块更清洁的方法,正如Hank指出的那样.
Bor*_* B. -1
C# 6 引入了when 异常过滤器,可以更好地控制应调用哪个 catch 块。接受when一个有权访问异常对象的表达式并返回一个布尔值。如果表达式产生false,则跳过该处理程序并考虑下一个处理程序:
try
{
var responseText = await streamTask;
return responseText;
}
catch (HttpRequestException e) when (e.Message.Contains("301"))
{
return "Site Moved";
}
catch (HttpRequestException e) when (e.Message.Contains("404"))
{
return "Page Not Found";
}
catch (HttpRequestException e)
{
return e.Message;
}
Run Code Online (Sandbox Code Playgroud)