首页 > 解决方案 > 在 C# try-finally 中如何捕获原始异常

问题描述

我的简单例子是:

    void FixedUnalterableMethod()
    {
        try
        {
            throw new Exception("Exception 1"); //line 12.
        }
        finally
        {
            throw new Exception("Exception 2"); //line 16.
        }
    }

    void Method1()
    {
        try
        {
            FixedUnalterableMethod(); //line 24.
        }
        catch (Exception ex)
        {
            var messageWithStackTrace = ex.ToString(); //line 28.
            Console.WriteLine(messageWithStackTrace);
        }
    }

控制台输出为:

System.Exception: Exception 2
    at Program.FixedUnalterableMethod() in ...\Program.cs:line 16
    at Program.Main(String[] args) in ...\Program.cs:line 24

问题是,如何得知Exception 1已经发生?有没有办法包含Exception 1在我的 StackTrace 中(第 28 行)?

当然我不能修改FixedUnalterableMethod()方法!

标签: c#.netexceptiontry-catchtry-finally

解决方案


是的,这是可能的,虽然很讨厌!

一个鲜为人知的事实是 CLR 异常finally在实际捕获到异常之前不会导致块的执行。这在某种程度上是伪装的,因为如果没有捕获异常(并使其脱离Main),则 CLR 托管代码的默认行为是finally为您运行块,从而产生它们始终运行的错觉。

但是,有一种方法可以在捕获异常之前对其进行检查,以决定是否要捕获它。试试这个:

static bool StoreFirstException(Exception x, Action<Exception> store)
{
    if (x.Message == "Exception 1")
    {
        store(x);                
    }

    return true;
}

static void Method1()
{
    Exception firstException = null;

    try
    {
        FixedUnalterableMethod(); //line 24.
    }
    catch (Exception ex) when (StoreFirstException(ex, x => firstException = x))
    {
        Console.WriteLine(firstException);               
        Console.WriteLine(ex);
    }
}

catch... when功能允许您编写一个布尔表达式来检查异常。在这里,我检查消息(您给我的唯一区别事实),如果它是第一个异常,我将其传递给store操作。

调用者使用此回调来存储第一个异常。

然后它投票给 catch,这只会导致finally块执行,这会引发第二个异常。相同的when子句对其进行了检查,但这次没有将其提供给store. 所以我在catch块中有两个例外,我把它们都记录下来。我的控制台使用正确的源代码行号显示了两个异常。

这是不查看消息的版本;它只是假设它看到的第一个异常一定是有趣的。使用嵌套函数也更整洁:

static void Method1()
{
    Exception firstException = null;

    bool StoreFirstException(Exception x)
    {
        if (firstException == null) firstException = x;
        return true;
    }

    try
    {
        FixedUnalterableMethod(); //line 24.
    }
    catch (Exception ex) when (StoreFirstException(ex))
    {
        Console.WriteLine(firstException);               
        Console.WriteLine(ex);
    }
}

推荐阅读