用条件捕获异常

chi*_*oro 8 c# syntax exception

注意:我很高兴地告诉您,异常过滤器现在使用的是C#6.0语言.

这是一个思想实验,我对你的观点感兴趣:这对你有意义吗?你知道C#编程语言是否已经提出了类似的东西吗?我甚至不知道在哪里提出这样的建议......

这个想法是引入语法元素,只有在满足特定条件时才能捕获异常.

一个用例示例是在使用COM Interop时:一切都会抛出一个COMException.实际区分错误代码包含在其消息中.

那么(提案1):

try
{
    ...
}
catch (COMException ex where ex.Message.Contains("0x800706BA"))
{
    // RPC server unavailable
}
catch (COMException ex where ex.Message.Contains("0x80010001"))
{
    // Call rejected by callee
}
Run Code Online (Sandbox Code Playgroud)

转换为:

try
{
    ...
}
catch (COMException ex)
{
    if (ex.Message.Contains("0x800706BA"))
    {
        // RPC server unavailable
    }
    else if (ex.Message.Contains("0x80010001"))
    {
        // Call rejected by callee
    }
    else
    {
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

类似的案例是:SoapException,XmlException......


另一种情况是异常被包装为一般异常中的内部异常,并且捕获逻辑应该依赖于内部异常.

假设我们有一个包含这样的异常的API : catch (NumberFormatException ex) { throw new BusinessException(ex) }.

怎么样(提案2A):

try
{
    ...
}
catch (inner NumberFormatException nfex)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

转换为:

catch (Exception ex where ex.InnerException is NumberFormatException)
{
    NumberFormatException nfex = ex.InnerException;
    ...
}
Run Code Online (Sandbox Code Playgroud)

或(2B):

catch (BusinessException bex inner NumberFormatException nfex)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

转换为:

catch (BusinessException bex where bex.InnerException is NumberFormatException)
{
    NumberFormatException nfex = bex.InnerException;
    ...
}
Run Code Online (Sandbox Code Playgroud)

这种情况下(最初来自Java)它看起来像(2C):

catch (RemoteAccessException raex inner inner MyException mex)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

小智 22

根据Visual Studio 2015 RCtry-catch C#参考,现在实现了:

Catch (ArgumentException e) when (e.ParamName == "…")
{
}
Run Code Online (Sandbox Code Playgroud)

  • 当(e.ParamName =="...)时,他们改变了是否捕获(例外e) (2认同)

sof*_*eda 8

VB.Net具有异常过滤器的这一功能,如下所示

Catch ex As COMException When ex.ErrorCode = 0x800706BA
Run Code Online (Sandbox Code Playgroud)

所以这得到了CLR的支持,但是这个功能没有在C#中公开

据说F#也有这个功能,但我不太了解F#来展示例子.

  • @leppie它肯定在CLR和IL级别得到支持.VB.Net和F#都有它.检查我之前评论中引用的博客帖子中的详细说明,该评论是关于CLR如何通过两次异常处理. (3认同)

Gor*_*yan 5

从 c# 7.0 开始就已经支持这种东西了。是完整的参考。这是代码片段。

    try
    {
        SomeOperationThatThrowsException();
    }
    catch(TheFilteredException ex ) when (ex.ErrorCode==123)
    {
        DoSomethingWhenExceptionThrown();
    }
Run Code Online (Sandbox Code Playgroud)


Sjo*_*erd 4

异常和类型紧密相关。如果要区分两种不同类型的异常,则应该创建两种异常类型。在您的示例中,您将有一个 Com800706BAException 和一个 Com80010001Exception。

现在,这并不总是可能或可行的,例如,如果底层系统使用错误代码而不是异常。在这种情况下,您的方法可能会有所帮助。然而,这种语言特性很容易被滥用。例如,您可以像这样进行错误处理,这不是类型安全的:

catch (Exception e where e.Message = "The foo barfed up the bar")
Run Code Online (Sandbox Code Playgroud)

如果您想检查异常的内部异常,那么您正在错误的级别上进行错误处理。这个想法是,方法抛出一个通用异常,将调用者从方法的内部工作中抽象出来。如果您依赖于某些内部异常,那么您将与该方法的实现紧密耦合。这不好。

要么应该抛出一个单独的通用异常,要么应该将错误处理移到方法内部。