C# 在使用异常过滤器进行日志记录时,如何避免“并非所有代码路径都返回值”

C# 在使用异常过滤器进行日志记录时,如何避免“并非所有代码路径都返回值”,c#,exception,logging,C#,Exception,Logging,注意:这是一个关于在使用异常过滤器进行日志记录时是否有最佳实践/惯用方法来避免特定编译器问题的问题。问题已经提到了两种不同的方法,以及每种方法的问题。如果可能的话,我正在寻找更好的方法 我使用一个异常过滤器和一个日志记录方法,该方法总是返回false到日志,但不捕获特定的异常: public string MyMethod() { try { // Do something. return "foo"; } catch (Speci

注意:这是一个关于在使用异常过滤器进行日志记录时是否有最佳实践/惯用方法来避免特定编译器问题的问题。问题已经提到了两种不同的方法,以及每种方法的问题。如果可能的话,我正在寻找更好的方法

我使用一个异常过滤器和一个日志记录方法,该方法总是返回false到日志,但不捕获特定的异常:

public string MyMethod()
{
    try
    {
        // Do something.
        return "foo";
    }
    catch (SpecificException ex) when (this.LogException(ex))
    {
        // Never hit.
    }
}
其中bool logexceptions specificeexception ex始终返回false

编译器不喜欢这样,并给我一个错误:CS0161不是所有的代码路径都返回一个值

我可以通过添加一个抛出来避免这个错误;在接球的内部,但是投掷永远不会被击中。 它最终看起来像一个冗余的catch异常{throw;},因此一个不在意的未来开发人员可能会删除整个catch

避免编译器错误的另一种方法是使用变量保存返回值,并将return语句移动到方法的末尾。然而,这将涉及将变量初始化为一个永远不会实际返回的值,并且再次无法像我希望的那样清楚地传达代码的意图


有没有更好的方法来避免这个编译器错误,即更清楚地传达代码将永远不会被命中,除了注释和冗余抛出

答案是否定的,您必须通过抛出或返回结果来满足编译器的静态分析

据我所知,您不能关闭此功能,也不能通过pragma禁用此错误

我认为你处于这种情况是因为滥用了一种语言功能。编译器完全希望when的条件是一个表达式,该表达式可能会导致true,也可能不会导致true。此外,考虑到静态分析的局限性,编译器反过来希望生成的块是有效的分支,即使您已硬连线将其关闭,并且认为它应该是编译错误


我会重新考虑你的设计是否可以预测,不会有副作用,如果你真的需要这样做,请使用注释和抛出的组合,或者按照建议返回结果。

如注释和其他答案中所述,如果要继续使用异常筛选器,正确的方法是在catch块内抛出异常,或返回null并添加注释,解释此处需要try/catch语句的原因:

// LogException() always returns false. The `catch` block is used exclusively for logging.
catch (SpecificException ex) when (this.LogException(ex)) { throw; }
如果使用异常过滤器的目的是维护原始StackTrace,您可以使用以下方法来绕过它:


可能添加注释:when this.LogExceptionex//Always false-专门用于日志记录。?返回null;在catch内部或try/catch块之后也会使其满意。在try之后返回默认值。.catch blocMaybe这是我不知道的事情,但是您当前正在执行的操作与catch specificeexception ex{this.LogExceptionex;throw;}之间是否存在差异?这清楚地表明,您确实需要捕捉块,并且做完全相同的事情,AFAICT。@AhmedAbdelhameed有一个微妙的区别,这里解释道:谢谢。在日志记录中使用异常过滤器的副作用是解释异常过滤器的一个常见例子,当它们第一次被引入时,我认为它可能已经变得流行起来,并且现在已经习惯了。您是否有重新思考设计的建议,或者您是否主张恢复捕获MyException ex{Logex;throw;}并记录所有其他兄弟捕获?@Ergwun是的,我希望这是一种更易于维护和预测的方法,这是一种方便的技术。谢谢。你可以通过简单的抛出来保持原来的堆栈跟踪;那么,ExceptionDispatchInfo.CaptureX.Throw的目的是什么;?
public string MyMethod()
{
    try
    {
        // Do something.
        return "foo";
    }
    catch (SpecificException ex)
    {
        this.LogException(ex);
        ExceptionDispatchInfo.Capture(ex).Throw();
        return null; // Redundant. Otherwise, the compiler will complain.
    }
}