不鼓励只捕获System.Exception。相反,只应捕获“已知”异常。
现在,这有时会导致不必要的重复代码,例如:
try
{
WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
WebId = Guid.Empty;
}
catch (OverflowException)
{
WebId = Guid.Empty;
}
我想知道:是否有一种方法可以捕获两个异常,并且只调用WebId=Guid.Empty调用一次?
给定的示例相当简单,因为它只是一个GUID。但是想象一下,在代码中,您多次修改一个对象,如果其中一个操作预期失败,您希望“重置”该对象。然而,如果有意外的异常,我仍然想把它推得更高。
这是马特的答案的变体(我觉得这有点干净)。。。使用一种方法:
public void TryCatch(...)
{
try
{
// something
return;
}
catch (FormatException) {}
catch (OverflowException) {}
WebId = Guid.Empty;
}
将引发任何其他异常,代码WebId=Guid.Empty;不会被击中。如果您不希望其他异常使您的程序崩溃,只需在其他两个捕获之后添加这个:
...
catch (Exception)
{
// something, if anything
return; // only need this if you follow the example I gave and put it all in a method
}
正如其他人所指出的,您可以在catch块中使用if语句来确定发生了什么。C#6支持异常过滤器,因此以下操作将起作用:
try { … }
catch (Exception e) when (MyFilter(e))
{
…
}
MyFilter方法可能看起来像这样:
private bool MyFilter(Exception e)
{
return e is ArgumentNullException || e is FormatException;
}
或者,这可以全部内联完成(when语句的右侧必须是布尔表达式)。
try { … }
catch (Exception e) when (e is ArgumentNullException || e is FormatException)
{
…
}
这与在catch块中使用if语句不同,使用异常过滤器不会展开堆栈。
您可以下载Visual Studio 2015来查看。
如果要继续使用Visual Studio 2013,可以安装以下nuget包:
安装程序包Microsoft.Net.Compilers
在撰写本文时,这将包括对C#6的支持。
引用此包将导致使用中包含的C#和Visual Basic编译器的特定版本与任何系统安装版本不同。
为了完整起见,自.NET 4.0以来,代码可以重写为:
Guid.TryParse(queryString["web"], out WebId);
TryParse从不抛出异常,如果格式错误,则返回false,将WebId设置为Guid.Empty。
由于C#7,您可以避免在单独的行中引入变量:
Guid.TryParse(queryString["web"], out Guid webId);
您还可以创建用于解析返回元组的方法,这些方法在.NET Framework 4.6版之前尚不可用:
(bool success, Guid result) TryParseGuid(string input) =>
(Guid.TryParse(input, out Guid result), result);
并像这样使用它们:
WebId = TryParseGuid(queryString["web"]).result;
// or
var tuple = TryParseGuid(queryString["web"]);
WebId = tuple.success ? tuple.result : DefaultWebId;
当在C#12中实现out参数的解构时,这个无用答案的下一个无用更新就来了
所以你在每个异常开关中重复了很多代码?听起来提取一个方法是个好主意,不是吗?
因此,您的代码归结为:
MyClass instance;
try { instance = ... }
catch(Exception1 e) { Reset(instance); }
catch(Exception2 e) { Reset(instance); }
catch(Exception) { throw; }
void Reset(MyClass instance) { /* reset the state of the instance */ }
我想知道为什么没有人注意到代码重复。
从C#6中,您还可以使用其他人已经提到的异常过滤器。因此,您可以将上面的代码修改为:
try { ... }
catch(Exception e) when(e is Exception1 || e is Exception2)
{
Reset(instance);
}