C# 比较异常

C# Compare Exceptions

提问人:vatbub 提问时间:3/2/2018 最后编辑:vatbub 更新时间:3/2/2018 访问量:8951

问:

我有一段代码,有时会抛出异常,有时不会。根据 IO 和网络的不同,可能会引发不同类型的异常。我有一个代码的包装器,它将重试失败的语句,比如 10 次,直到它成功。如果异常在第 10 次后没有消失,我会重新抛出它。直到现在,我知道该怎么做。 目前,我有这样的东西:

private void ExecuteStatement(Action statementToExecute)
{
    while (true)
    {
        int exceptionCount = 0;
        try
        {
            statementToExecute.Invoke();
            // statement finished successfully
            break;
        }
        catch (Exception e)
        {
            if (!IsFrameworkException(e))
                throw; // rethrow as it isn't a framework exception

            // we know now that it's a framework exception
            exceptionCount++;
            if (exceptionCount >= MaxRetriesOnFrameworkException)
                throw;
        }
    }
}

问题如下:我想重置计数器,以防异常发生变化(即不同的类型、不同的堆栈跟踪、不同的消息)。我知道如何单独比较它们,但我想知道是否有标准的 C# 方法可以实现这一点。

编辑:这是代码:IsFrameworkException

private bool IsFrameworkException(Exception e)
{
    Exception rootCause = e.GetBaseException();
    return rootCause.GetType() == typeof(WebException);
}
c#

评论

2赞 W0RT4 3/2/2018
您可以将 miltiple catch 用于不同的异常类型
0赞 Chetan 3/2/2018
你能分享一下方法的代码吗?IsFrameworkException
0赞 Camilo Terevinto 3/2/2018
我只会这样做string message = string.Empty; .... exceptionCount++; if (exceptionMessage == ex.Message) { ... }
0赞 vatbub 3/2/2018
我不能使用多个 catch 子句,因为抛出的异常大多是具有不同内部异常的类型。 仅对异常类型和消息进行一些简单的检查,以查看它们是否与框架异常的模式匹配System.ExceptionIsFrameworkException

答:

3赞 Igor 3/2/2018 #1

应指定要捕获的异常类型。按最具体类型到最通用类型的顺序放置 catch 块。

目前尚不清楚这些异常是否都源自 ,或者是否要使用 ,以下假设是前者。FrameworkExceptionException

int exceptionCount = 0;
Type lastCaughtException = null;
while(true) {
  try
  {
    statementToExecute.Invoke();
    // statement finished successfully
    break;
  }
  catch (WebException ex)
  {
    if(lastCaughtException == null || lastCaughtException != ex.GetType())
        exceptionCount = 0;
    else
        exceptionCount++;

    lastCaughtException = ex.GetType();
    if (exceptionCount >= MaxRetriesOnFrameworkException)
        throw;
  }
  catch (Exception) // if you do not want to log this you can completely omit this catch
  {
    throw; // rethrow as it isn't a framework exception
  }
}

另请参见 try-catch(C# 参考)

评论

2赞 Camilo Terevinto 3/2/2018
虽然是一个很好的建议,但它并不能解决在异常发生变化时重置计数的问题
0赞 Camilo Terevinto 3/2/2018
只是想知道,什么是 FrameworkException
0赞 vatbub 3/2/2018
谢谢,但同样,我无法指定特定的异常类型,因为这些框架异常会伪装成具有更解释性的消息或内部异常。这就是为什么我需要在 catch 块中比较它并且不能使用多个 catch 子句的原因System.Exception
0赞 Igor 3/2/2018
@vatbub - 根据您的 IsFrameworkException 代码,您所要做的就是 catch .异常捕获基于继承工作,如果这是您感兴趣的根类型,那么请捕获它。WebException
0赞 Igor 3/2/2018
@vatbub - 老实说,虽然你应该为你知道的代码应该从中恢复的内容编写处理程序,但其他所有内容都应该不被捕获或(记录并重新抛出)。如果您尝试忽略自己的自定义异常,则最好记录您正在调用的内容可以引发的内容,并筛选这些异常,以便重新抛出它们,并让其他所有内容由基本异常类型 System.Exception 处理。
3赞 vgru 3/2/2018 #2

这与异常处理没有特别关系,但按特定键保留计数器的一种简单方法是使用 a 作为键(它实现了开箱即用的值相等)。Tuple

请注意,这不会在密钥更改时重置计数器,它只是为每个密钥保留单独的计数器:

readonly Dictionary<Tuple<Type, string, string>, int> _counters = 
     new Dictionary<Tuple<Type, string, string>, int>();

bool IsCountExceeded(Exception ex)
{
    // create your key with whatever properties you consider to 
    // be "unique"
    var key = Tuple.Create(ex.GetType(), ex.StackTrace, ex.Message);

    // increase counter 
    int counter;
    if (!_counters.TryGetValue(key, out counter))
    {
        counter = 1;
    }
    else
    {
        counter++;
    }
    _counters[key] = counter;

    return counter > Max;
}

当然,你总是可以通过创建自己的类来使其更具可读性,这将正确实现 /。EqualsGetHashCode

我也不确定堆栈跟踪是否可以被视为唯一属性,当然,捕获和忽略异常通常是一个坏主意。

评论

0赞 vatbub 3/2/2018
我不会忽略它们,我只是省略了日志记录代码,因为它并不那么有趣。我面临的情况是 UI 测试,由于 UITest 框架做了奇怪的事情,这些测试是不稳定的。由于框架的原因,这会导致测试失败。为了避免这种情况,我想捕获异常并重试。