代码之家  ›  专栏  ›  技术社区  ›  user1185417

C#是否有办法知道是否已捕获异常

  •  0
  • user1185417  · 技术社区  · 7 年前

    是否有方法确定以前是否捕获过异常(并重试)?例如:

    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块中,是否有方法确定子函数中是否已经捕获了异常?

    2 回复  |  直到 7 年前
        1
  •  4
  •   InBetween    7 年前

    我会创建一个自定义 LoggedException 然后把它扔到堆栈上:

    catch (Exception ex)
    {
         Log(ex);
         throw new LoggedException(ex);
    }
    
        2
  •  2
  •   Jon Skeet    7 年前

    虽然我不确定我会推荐这样做,但您可以修改 Exception.Data 所有物如果您的 LogError 方法接受异常并以允许您稍后检查的方式对其进行修改,这应该对您有用。

    注意,这允许代码的其余部分 关注日志方面,而不是中间人的答案。例如,您可能有一些代码希望捕获基于类型的异常,我觉得“将异常标记为已记录”应该与此正交。如果要更改引发的异常类型,则可能会以与日志记录无关的方式进一步更改堆栈中代码的行为。

    下面是一个示例:

    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
    }