C# 如何明确不抛出异常?

C# 如何明确不抛出异常?,c#,.net,exception,C#,.net,Exception,这可能是一个广泛的问题,但最近我想知道以下几点:在我们的C#后端,我们有许多地方将一些代码包装在try/catch块中,特别是对外部WcF服务的调用。其中一些调用对应用程序至关重要,因此在catch块中,我们记录错误并重试,如: catch(Exception ex) { _logger.Error("Some good error message"); throw ex; } 另一方面,我们允许某些服务失败,但我们仍希望记录错误,因此它们看起来像: catch(Excepti

这可能是一个广泛的问题,但最近我想知道以下几点:在我们的C#后端,我们有许多地方将一些代码包装在
try
/
catch
块中,特别是对外部WcF服务的调用。其中一些调用对应用程序至关重要,因此在catch块中,我们记录错误并重试,如:

catch(Exception ex)
{
    _logger.Error("Some good error message");
    throw ex;
}
另一方面,我们允许某些服务失败,但我们仍希望记录错误,因此它们看起来像:

catch(Exception ex)
{
    _logger.Error("Some good error message");
}
现在阅读团队成员守则,我无法确定他们是否忘记投掷,或者这是否是预期的行为


问:有办法吗。默认的方式是什么,显式不重新引用(代码中不包含注释)

我曾经考虑过这样的事情:

catch(Exception ex)
{
    _logger.Error("Some good error message");
    NotThrowingHereOnPurpose();
}

// ...
// and further below a private method
// ...

private void NotThrowingHereOnPurpose(){}

这里可能有用的一种方法是更改调用代码的方式,您明确允许该代码以这样的方式失败,即它看起来根本不像一个
try
/
catch

例如,您可以编写一个执行错误报告的helper方法,并使用表示为lambdas的操作调用它:

void InvokeFailSafe(Action action, Action<Exception> onFailure = null) {
    try {
        action();
    } catch (Exception e) {
        if (onFailure != null) {
            onFailure(e);
        }
    }
}
或者像这样,如果您不想记录任何内容:

InvokeFailSafe(
    () => {
        ... The code that may fail
    }
);
如果您以这种方式编写代码,毫无疑问会丢失
throw
语句

问:有办法吗。默认的方式是什么,显式不
重新引用(代码中不包含注释)

理想的方法是不捕获一般异常。现在,投不投完全取决于你的情况。您需要了解,当您知道发生异常时应该做什么时,就会使用异常处理。因此,只应处理特定的异常。在不知道捕获的内容的情况下捕获异常将更改应用程序的行为

现在阅读团队成员的代码,我不能确定他们是否忘记了 投掷或如果这是预期的行为

这是代码的作者可以向您解释的。但这里有一个可以从中吸取的教训。您的代码应该是自解释的。在无法用代码表达自己的特定情况下,请添加有意义的注释


你可以检查一下,以便更好地理解。

这与dasblinkenlight的答案相反。它不会通知其他人该异常不能被重新引用,而是会说它必须被重新引用

如果您只想记录它,那么像往常一样使用
Error
方法。否则,您可以为记录器编写一个扩展方法来记录和抛出异常

该方法将获取捕获的异常,并使用类重新引用它。
异常DispatchInfo
用于使用原始堆栈跟踪信息和Watson信息重新显示异常。它的行为类似于
throw(没有指定的异常)

并以这种方式使用它:

try
{
}
catch (Exception ex)
{
    // ex would be rethrown here
    _logger.ErrorAndThrow("Some good error message", ex);
}

这不应该经常出现。考虑

string WebGreeting()
{
  try
  {
     return _greetingService.HelloWorld();
  }
  catch(Exception ex)
  {
      _logger.Error("Some good error message");
      //throw;  // when this is missing, you get the compiler error "not all paths ..."
  }
  // unless you very deliberately code the on-error case
  // return "nothing";
}

这就留下了奇数
无效的
方法。但这真的是你的问题吗?

我实际上找到了另一种方法,它包含了其他人在这里提出的建议,但使用了一个内置功能:异常过滤器。我可以随意修改中给出的示例来说明这一点:

public void MethodThatFailsSometimes()
{
    try {
        PerformFailingOperation();
    } 
    catch (Exception e) when (e.LogAndBeCaught())
    {
    }
}
然后在
Exception
上可以有两种扩展方法,比如
LogAndBeCaught
logandscape
,如下所示:

public static bool LogAndBeCaught(this Exception e)
{
    _logger.Error(@"Following exception was thrown: {e}");
    return true;
} 

public static bool LogAndEscape(this Exception e)
{
    _logger.Error(@"Following exception was thrown: {e}");
    return false;
} 

“在代码中不包含注释”-为什么不?我能想到的最接近的事情是某些解析方法中的明确区别,例如
int.Parse
int.TryParse
。也许这对你有用。最后,我想命名规则取决于你?第二种方法就是这样做的。注释是在代码中“解释”任何内容的方式。其他任何事情都是人类的问题。用
throw重新抛出
not
throw ex
创建新堆栈跟踪,我想您希望保留异常真正发生的位置的信息。调用假方法时,有什么更好的方法可以调用
notthrowingherewhere目的
而不是添加可读文档?没有默认的方法,如果您想要吞下异常(只记录它),那么这就是方法的实现方式。如有必要,添加注释。另一方面,重新引用每个异常并不是默认的方式。我试图在上面的代码中从问题中抽象出太多内容,试图把问题弄清楚,但我似乎失败了。。。事实上,我只捕捉特定的例外情况,我希望这个问题适用于此,而不是一般的。谢谢你的回答。事实上,我也在考虑创建一个这样的方法转发器……考虑更改OntRebug有一个默认的<代码> null <代码>,然后在调用它之前做一个空检查。这样,呼叫者就可以不传递任何信息来表示“我不关心这里的异常”。@mjwills你到底为什么要让异常易于接受?这是一件不应该做的事情,或者是非常罕见的事情,你希望人们特意去做,以表明他们真的想这么做。@Servy,这当然是一个可以辩护的论点。一个可能的反驳是,只接受异常已经很容易了(即,只做一个空的catch块)。如果你真的担心,您可以将问题分为两部分,一部分是
InvokeFailSafe
,另一部分是
InvokeFailSafe和snownexExceptions
,以使其更加明确。@mjwills一个空的
catch
块对于任何有能力的程序员来说都是一个巨大的危险信号,几乎肯定是错误的这需要立即关注。对于所有程序员来说,看到只使用一个参数而不是两个参数调用
InvokeFailSafe
,并不会以同样的方式脱颖而出。此外,该名称还意味着它能够安全地发生故障,即使它无法采取任何行动
public void MethodThatFailsSometimes()
{
    try {
        PerformFailingOperation();
    } 
    catch (Exception e) when (e.LogAndBeCaught())
    {
    }
}
public static bool LogAndBeCaught(this Exception e)
{
    _logger.Error(@"Following exception was thrown: {e}");
    return true;
} 

public static bool LogAndEscape(this Exception e)
{
    _logger.Error(@"Following exception was thrown: {e}");
    return false;
}