sta*_*low 32 c# exception-handling exception c#-6.0
C#6有一个名为"异常过滤"的新功能
语法是这样的:
catch (Win32Exception exception) when (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
Run Code Online (Sandbox Code Playgroud)
我不禁想知道当前的方法有什么好处:
catch (Win32Exception exception)
{
if (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
}
Run Code Online (Sandbox Code Playgroud)
在大括号之前进行过滤是一件大事吗?也许与性能或安全性有关?
i3a*_*non 33
C#6.0中的异常过滤器功能提供了各种好处.这是对一些的解释(按我认为的重要性排序)
功能奇偶校验 - 异常过滤器已经在IL级别和其他.Net语言(VB.Net和F#)[1]中实现,并且作为构建C#和VB.Net(项目"Roslyn")的新编译器的一部分,许多功能以一种语言存在而另一种语言缺乏[2].
崩溃转储 - 异常过滤器不会修改堆栈.这意味着如果它被转储(在崩溃转储中),你将能够知道最初抛出异常的位置,而不仅仅是它被重新抛出的位置(这与实际问题无关)[3]
调试 -当异常进入catch
块,重新抛出使用throw;
,并且堆栈不处理其他地方(和例外设置被设置为打破时异常是用户未处理)调试器将打破throw;
,而不是其中的例外是最初抛出(即在下面的例子中,它会破坏throw;
而不是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
}
Run Code Online (Sandbox Code Playgroud)可读性 - 虽然您可以使用catch
具有许多条件的"catch all" 块并且throw;
当它们不被满足时(同时对堆栈进行修改),但是使用单独且不同的catch
块更清楚,其中每个块以适当的方式处理特定问题:
try
{
}
catch (Win32Exception exception) when (exception.NativeErrorCode == 0x00042)
{
}
catch (Win32Exception exception) when (exception.NativeErrorCode == 0x00011)
{
}
catch (IOException)
{
}
Run Code Online (Sandbox Code Playgroud)"滥用" - 您可以使用异常过滤器来检查异常而不处理它.虽然这不是主要的好处,但它是一个很好的副作用.您可以使用错误返回的日志记录方法和空catch
块:
private static bool LogException(Exception exception)
{
Console.WriteLine(exception.Message);
return false;
}
try
{
}
catch (ArgumentException exception) when (LogException(exception))
{
// Unreachable code.
}
Run Code Online (Sandbox Code Playgroud)总之,大多数C#6.0功能都是小改进和语法糖,虽然异常过滤器不是一个非常大的功能,它确实提供了以前无法实现的功能.
C#6.0中的另一个例外改进 - 支持异常过滤器 - 使语言与其他.NET语言(即Visual Basic .NET和F#)保持同步
异常过滤器比捕获和重新抛出更可取,因为它们可以保持堆栈不受破坏.如果稍后的异常导致堆栈被转储,您可以看到它最初来自哪里,而不仅仅是它重新抛出的最后一个位置.
Tho*_*que 12
ErenErsönmez已经提到了最重要的好处.
我只想补充说,当捕获异常时,它具有展开堆栈的效果.这意味着如果你重新抛出异常throw;
并且它没有被捕获到堆栈的更高位置,调试器将突出显示throw
,而不是最初抛出异常的位置,因此当异常时你无法看到变量的状态被扔了.
另一方面,异常过滤器不会展开堆栈,因此如果未捕获异常,调试器将显示最初抛出异常的位置.
所以,如果你有这个:
try
{
DoSomethingThatThrows();
}
catch (Win32Exception exception)
{
if (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
else
{
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
throw
当NativeErrorCode
不是0x42 时,调试器将停止.
但如果你有这个:
try
{
DoSomethingThatThrows();
}
catch (Win32Exception exception) if (exception.NativeErrorCode == 0x00042)
{
//Do something here
}
Run Code Online (Sandbox Code Playgroud)
调试器将停止DoSomethingThatThrows
(或在它调用的方法中),让你更容易看到导致错误的原因(同样,当NativeErrorCode
不是0x42时)
从官方C#功能描述(PDF下载链接,如VS2015预览版):
异常过滤器比捕获和重新抛出更可取,因为它们可以保持堆栈不受破坏.如果稍后的异常导致堆栈被转储,您可以看到它最初来自哪里,而不仅仅是它重新抛出的最后一个位置.
使用异常过滤器进行副作用也是一种常见且被接受的"滥用"形式; 例如伐木.他们可以在不拦截其路线的情况下检查"飞过"的异常.在这些情况下,过滤器通常会调用一个错误返回的辅助函数来执行副作用:
Run Code Online (Sandbox Code Playgroud)private static bool Log(Exception e) { /* log it */ ; return false; } … try { … } catch (Exception e) if (Log(e)) {}
真正的好处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
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5302 次 |
最近记录: |