【问题标题】:in C# try-finally how to catch the original exception在 C# try-finally 中如何捕获原始异常
【发布时间】:2019-12-23 22:18:52
【问题描述】:

我的简单例子是:

    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 已经发生? 有没有办法在我的 StackTrace 中包含 Exception 1(第 28 行)?

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

【问题讨论】:

  • 不,你不能。抛出异常 2 时,异常 1 被丢弃。
  • 为什么要在finally中抛出异常?你有一个总是想失败的方法,这似乎很奇怪。
  • @John FixedUnalterableMethod 方法在外部 dll 中,我无法更改。但是我想知道Exception 1已经发生了。

标签: c# .net exception try-catch try-finally


【解决方案1】:

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

一个鲜为人知的事实是 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 操作。

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

然后它投票捕获,这只会导致 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);
    }
}

【讨论】:

  • 这太棒了!一个可爱的小块几乎总是无用但引人入胜的信息
  • 非常有趣,找到这样的语言功能总是令人惊奇。感谢您的详细解释!
【解决方案2】:

如果“异常类型”实际上是相同的,您可能别无选择,只能检查 Message 属性,这至少可以说是有问题的。

再次查看该代码,无论如何您只会看到 1 个异常,即第 16 行的异常。

【讨论】:

    【解决方案3】:

    感谢@Daniel Earwicker,工作解决方案是:

    void FixedUnalterableMethod()
    {
        try
        {
            throw new Exception("Exception 1"); //line 12.
        }
        finally
        {
            throw new Exception("Exception 2"); //line 16.
        }
    }
    
    void Method1()
    {
        bool CatchException(Exception ex)
        {
            //Log...
    
            Console.WriteLine(ex.ToString());
            return true;
        }
    
        try
        {
            FixedUnalterableMethod(); //line 24.
        }
        catch (Exception ex) when (CatchException(ex))
        {
            //do something with the lastest exception
        }
    }
    

    【讨论】:

    • 所以传统上在这一点上你会接受我的回答!无需发布它的另一个副本。 :)
    猜你喜欢
    • 1970-01-01
    • 2013-12-05
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 2014-01-08
    相关资源
    最近更新 更多