【问题标题】:C# Is there way to know if an exception was already caughtC#有没有办法知道是否已经捕获了异常
【发布时间】:2018-04-04 16:07:54
【问题描述】:

有没有办法确定之前是否已捕获(并重新抛出)异常?例如:

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 函数中捕获?

【问题讨论】:

  • 您可以包装异常,然后使用catch (Exception ex) when (!(ex is MyExceptionType))。或者,您也许可以检查堆栈跟踪。 (参见 System.Diagnostics 命名空间)。
  • 您可以使用自定义类型的 Exception 扩展 Exception,您可以在其中留下该信息。
  • 抛出一些自定义异常并在父级忽略它
  • 是的,我就是这么想的,但我想知道是否有内置的方法来解决这个问题。
  • 没有内置方式

标签: c# .net exception


【解决方案1】:

我会创建一个自定义 LoggedException 并将其扔到堆栈中:

catch (Exception ex)
{
     Log(ex);
     throw new LoggedException(ex);
}

【讨论】:

    【解决方案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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-07
      • 2019-11-17
      • 1970-01-01
      • 2019-05-17
      • 2019-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多