有没有办法确定先前是否已捕获(并重新抛出)异常?例如:
public void Main()
{
try
{
Child();
}
catch( Exception ex)
{
// do something only if exception was not already in another catch block
}
}
public void Child()
{
try
{
A_ThisMayThrowException();
}
catch (Exception ex)
{
LogError();
throw;
}
B_ThisMayAlsoThrowAnErrorButWillNotBeCaughtHere();
}
在Main函数中,在catch块中,有没有办法确定是否已在Child函数中捕获到异常?
答案 0 :(得分:4)
我会创建一个自定义LoggedException
并将其抛出堆栈:
catch (Exception ex)
{
Log(ex);
throw new LoggedException(ex);
}
答案 1 :(得分:2)
虽然我不确定我是否建议这样做,但您可以修改Exception.Data
属性返回的字典。如果您的LogError
方法接受异常并以允许您稍后检查的方式对其进行修改,则该方法适用于您。
请注意,与InBetween的答案不同,这允许其余代码不关心日志记录方面。例如,您可能有一些代码想要根据类型捕获异常 - 我觉得像“将记录的异常标记为已记录”的部分应与此正交。如果您正在更改抛出的异常类型,那么可以以与日志记录无关的方式更改堆栈中的代码行为。
以下是一个例子:
using System;
class Test
{
static void Main()
{
TestHandling(true);
TestHandling(false);
}
static void TestHandling(bool throwFirst)
{
try
{
Child(throwFirst);
}
catch (Exception ex)
{
Console.WriteLine($"Previously caught? {ex.Data.Contains("Logged")}");
}
}
static void Child(bool throwFirst)
{
try
{
if (throwFirst)
{
throw new Exception();
}
}
catch (Exception ex)
{
Console.WriteLine("Logging!");
ex.Data["Logged"] = true;
throw;
}
throw new Exception();
}
}
输出:
Logging!
Previously caught? True
Previously caught? False
这种方法也适用于异常过滤器,你甚至可以只记录一次。例如:
public bool LogAndThrow(Exception ex)
{
if (!ex.Data.Contains("Logged"))
{
// Replace with real logging
Console.WriteLine("An exception occurred!");
ex.Data["Logged"] = true;
}
// Always continue up the stack: this never filters
return false;
}
public static bool CatchIfNotLogged(this Exception ex) =>
!ex.Data.Contains("Logged");
然后你可以:
try
{
Foo();
}
catch (Exception ex) when (ex.CatchIfNotLogged()
{
// We only get here if the exception hasn't been logged
}
和
try
{
Foo();
}
catch (Exception ex) when (ex.LogAndThrow())
{
// We never get here
}