C#6有一个名为"异常过滤"
的新功能语法如下:
catch (Win32Exception exception) when (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
我无法帮助,但不知道这对当前的方法有什么好处:
catch (Win32Exception exception)
{
if (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
}
在大括号之前进行过滤是否很重要?也许与绩效或安全有关?
答案 0 :(得分:33)
C#6.0中的异常过滤器功能提供了各种好处。这是对某些人的解释(按我认为的重要性排序)
功能奇偶校验 - 异常过滤器已在IL级别和其他.Net语言(VB.Net& F#) [1] 中实现,作为构建C#和VB.Net的新编译器(项目" Roslyn")的一部分,一种语言中存在的许多功能和另一种语言中缺少的功能都是 [2] 。
崩溃转储 - 异常过滤器不会修改堆栈。这意味着如果它被转储(在崩溃转储中),您将能够知道最初抛出异常的位置,而不仅仅是重新抛出的位置(这与实际问题无关) [3]
调试 - 当异常进入catch
块时,使用throw;
重新抛出并且不会在堆栈中的任何其他位置处理(并且异常设置被设置为在用户未处理异常时中断)调试器将在throw;
而不是最初抛出异常的地方中断(即在下面的示例中,它将在throw;
而不是{{ 1}})
多个throw new FileNotFoundException();
块 - 如果没有异常过滤器,您必须捕获异常,检查条件以及是否未遇到catch
异常。即使异常满足最终导致单个大throw;
块的所有条件,重新抛出的异常也不会考虑任何其他catch
块
catch
可读性 - 虽然你可以使用"赶上所有" try
{
throw new FileNotFoundException();
}
catch (FileNotFoundException e)
{
if (!e.FileName.Contains("Hamster"))
{
throw;
}
// Handle
}
catch (Exception e)
{
// Unreachable code
}
阻止了很多条件而catch
当它们未被满足时(虽然对堆栈进行了修改),每个句柄都有单独且不同的throw;
块更清楚以适当方式解决的具体问题:
catch
"滥用" - 您可以使用异常过滤器来检查异常而不处理异常。虽然这不是一个主要的好处,但它是一个很好的副作用。您可以使用错误返回的日志记录方法和空的try
{
}
catch (Win32Exception exception) when (exception.NativeErrorCode == 0x00042)
{
}
catch (Win32Exception exception) when (exception.NativeErrorCode == 0x00011)
{
}
catch (IOException)
{
}
块:
catch
总之,大多数C#6.0功能都是小改进和语法糖,虽然异常过滤器不是一个非常大的功能,它确实提供了以前不可能实现的功能。
C#6.0的另一个例外改进 - 支持异常过滤器 - 使语言与其他.NET语言保持同步,即Visual Basic .NET和F#
异常过滤器比捕获和重新抛出更可取,因为它们可以保持堆栈不受破坏。如果异常稍后导致堆栈被转储,您可以看到它最初的来源,而不仅仅是它重新抛出的最后一个位置。
答案 1 :(得分:12)
我只想补充一点,当捕获异常时,它具有展开堆栈的效果。这意味着如果您使用throw;
重新抛出异常并且它没有被捕获到堆栈的更高位置,则调试器将突出显示throw
,而不是最初抛出异常的位置,因此您可以'在抛出异常时看到变量的状态。
另一方面,异常过滤器不展开堆栈,因此如果未捕获异常,调试器将显示最初抛出异常的位置。
所以如果你有这个:
try
{
DoSomethingThatThrows();
}
catch (Win32Exception exception)
{
if (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
else
{
throw;
}
}
当throw
不是0x42时,调试器将在NativeErrorCode
停止。
但如果你有这个:
try
{
DoSomethingThatThrows();
}
catch (Win32Exception exception) if (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
调试器将在DoSomethingThatThrows
中停止(或在其调用的方法中),让您更容易看到导致错误的原因(同样,当NativeErrorCode
不是0x42时)
答案 2 :(得分:7)
来自官方C# feature descriptions(PDF下载链接,与VS2015预览一样):
异常过滤器比捕获和重新抛出更可取,因为 他们没有受到伤害。如果异常后来导致堆栈 要被倾倒,你可以看到它最初的来源,而不是 只是最后一个地方被重新抛出。
使用例外也是一种常见且被接受的“滥用”形式 过滤器的副作用;例如日志记录。他们可以检查异常 “飞过”而没有拦截它的路线。在那些情况下, filter通常会调用一个错误返回的辅助函数 执行副作用:
private static bool Log(Exception e) { /* log it */ ; return false; } … try { … } catch (Exception e) if (Log(e)) {}
答案 3 :(得分:6)
它允许检查条件而不捕获异常,这意味着如果不满足条件,则考虑下一个catch块。如果你抓住并重新投掷,则不会考虑下一个拦截区块。
答案 4 :(得分:5)
真正的利益IMO:
try
{
}
catch (SomeException ex) if (ex.Something)
{
}
catch (Exception ex)
{
// SomeException with !ex.Something is caught here
// not the same as calling `throw` for !ex.Something
// without filters in previous handler
// less code duplication
}