提问人:vatbub 提问时间:3/2/2018 最后编辑:vatbub 更新时间:3/2/2018 访问量:8951
C# 比较异常
C# Compare Exceptions
问:
我有一段代码,有时会抛出异常,有时不会。根据 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);
}
答:
3赞
Igor
3/2/2018
#1
应指定要捕获的异常类型。按最具体类型到最通用类型的顺序放置 catch 块。
目前尚不清楚这些异常是否都源自 ,或者是否要使用 ,以下假设是前者。FrameworkException
Exception
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;
}
当然,你总是可以通过创建自己的类来使其更具可读性,这将正确实现 /。Equals
GetHashCode
我也不确定堆栈跟踪是否可以被视为唯一属性,当然,捕获和忽略异常通常是一个坏主意。
评论
0赞
vatbub
3/2/2018
我不会忽略它们,我只是省略了日志记录代码,因为它并不那么有趣。我面临的情况是 UI 测试,由于 UITest 框架做了奇怪的事情,这些测试是不稳定的。由于框架的原因,这会导致测试失败。为了避免这种情况,我想捕获异常并重试。
评论
IsFrameworkException
string message = string.Empty; .... exceptionCount++; if (exceptionMessage == ex.Message) { ... }
System.Exception
IsFrameworkException