简体   繁体   English

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

[英]C# Is there way to know if an exception was already caught

Is there a way to determine if an exception was previously caught (and rethrown)? 有没有办法确定以前是否捕获过异常(并重新抛出了异常)? For exemple: 举个例子:

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();


}

In the Main function, in its catch block, is there a way to determine if the exception was already caught in the Child function? 在Main函数的catch块中,是否有办法确定Child函数是否已捕获异常?

I would create a custom LoggedException and throw it up the stack: 我将创建一个自定义LoggedException并将其抛出堆栈:

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

While I'm not sure I'd recommend this, you can modify the dictionary returned by the Exception.Data property. 虽然不确定我是否会建议这样做,但是您可以修改Exception.Data属性返回的字典。 If your LogError method were to accept the exception and modify it in a way that allowed you to check later, that should work for you. 如果您的LogError方法接受异常并以允许您稍后检查的方式对其进行修改,则该方法将对您LogError

Note that this allows the rest of the code not to care about the logging aspect, unlike InBetween's answer. 请注意,这与InBetween的答案不同,这使其余代码无需关心日志记录方面。 For example, you may have some code that wants to catch exceptions based on type - it feels to me like the part about "marking an exception as logged" should be orthogonal to that. 例如,您可能有一些想要根据类型捕获异常的代码-在我看来,“将异常标记为已记录”部分应该与此正交。 If you're changing the type of exception being thrown, that can change behavior of code further up in the stack in a fashion which is unrelated to logging. 如果要更改所引发的异常的类型,则可以以与日志记录无关的方式在堆栈中进一步更改代码的行为。

Here's an example: 这是一个例子:

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();
    }
}

Output: 输出:

Logging!
Previously caught? True
Previously caught? False

This approach would work with exception filters as well, and you could even make it only log once, as well. 这种方法也可以与异常过滤器一起使用,甚至可以使它仅记录一次。 For example: 例如:

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");

Then you could have: 然后,您可能会:

try
{
    Foo();
}
catch (Exception ex) when (ex.CatchIfNotLogged()
{
    // We only get here if the exception hasn't been logged
}

and

try
{
    Foo();
}
catch (Exception ex) when (ex.LogAndThrow())
{
    // We never get here
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM