我有一个 try..catch 块,如下所示:
try
{
...
}
catch (IOException ioEx)
{
...
}
catch (Exception ex)
{
...
}
我只想处理某种类型的
IOException
,即共享冲突(Win32 0x20)。其他 IOException 和所有其他 Exception
后代通常应由第二个 catch-all catch 处理。
一旦我知道 IOException 不是共享冲突,我怎样才能干净地将错误处理流程重定向到常规
catch
?如果我重新抛出 catch (IOException)
,第二个 catch 不会调用。我知道我可以嵌套尝试..捕获但是有更干净的方法吗?
在方法中分解重复的代码肯定会起作用,但我注意到,一般来说,当您使用分解方法进行异常处理时,它往往会出现微妙的问题。
首先,
catch
子句可以直接访问异常发生之前的所有局部变量。但是,当您将异常处理“外包”给不同的方法时,您必须将状态传递给它。当您更改代码时,处理程序方法的签名也会更改,这在更复杂的场景中可能会成为可维护性问题。
另一个问题是程序流程可能会变得模糊。例如,如果处理程序方法最终重新抛出异常,C# 编译器和 Resharper 等代码分析器将看不到它:
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
}
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"
);
...!
}
}
如果我想避免这类(小)问题,那么似乎没有比嵌套 try..catch 块更干净的方法了,正如 Hank 指出的那样。
只需将处理逻辑分解到一个单独的方法中即可。
try
{
...
}
catch (IOException ioEx)
{
if (sharing violation)
HandleSharingViolation();
else
HandleNonsharingViolation();
}
catch (Exception ex)
{
HandleNonsharingViolation();
}
或者自己测试异常情况
catch (Exception ex)
{
if (ex is IOException && ex.IsSharingViolation()
HandleSharingViolation();
else
HandleNonsharingViolation();
}
不,你必须筑巢。
一旦进入其中一个 catch 块,该“try”就被视为已处理。
我认为这可能很有意义,“共享违规”听起来像是一种特殊情况,可能并不像您想象的那样与其他情况紧密耦合。如果您使用嵌套 try-catch,特殊情况的 try 块是否必须包围exact相同的代码?当然,它是一个可以重构为单独方法的候选者。
创建方法来处理异常,将异常传递给该方法,根据类型以您想要的方式处理异常。在这两个块中调用这些方法。
使用嵌套的 try catch 块。
try
{
try
{
}
catch (IOException ioEx)
{
if (....)
else
throw;
}
}
catch
{
}
“终于”呢?
一旦知道 IOException 不存在共享冲突,您就可以首先在 IOException 块中设置一个“变量”。然后,在您的finally块中,如果设置了该“变量”,您就可以继续执行您需要执行的操作。
bool booleanValue = false;
try
{
test1(); // this would thro IOException
}
catch (IOException e)
{
booleanValue = true; // whatever you need to do next
}
finally
{
if (booleanValue)
{
Console.WriteLine("Here");
}
}
尝试这个嵌套块
尝试
{
}
catch(异常ioex)
{
尝试
{
}
捕获(异常前)
{
}
}
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;
}