Mono:如何(重新)抛出异常,保留原始堆栈跟踪信息并收集本地数据

本文关键字:信息 跟踪 数据 堆栈 原始 如何 重新 保留 抛出异常 Mono | 更新日期: 2023-09-27 18:01:14

我递归地处理分层数据。如果出现问题,我想收集堆栈展开的额外信息(导致异常的节点路径(。我想保留原始的异常消息和堆栈跟踪。这应该是一个很受欢迎的任务,但我在.NET中找不到任何支持。我该如何实现它?

我试图捕捉异常并重新引发我自己的异常,在递归函数中提供额外的数据,或者在原始异常exception.data中存储额外的数据。问题是我没有设法提供正确的堆栈跟踪,其中应该包括原始异常堆栈跟踪+我的递归函数调用的堆栈跟踪展开到我处理异常的地方。

我的代码看起来像:

void func(...)
{
    try
    {
         ...
         func(...);
    }
    catch (Exception ex)
    {
        Rethrow(ex, localData);
    }
}

Rethrow()如何实现?

编辑:

我发现这种情况只发生在Mono中,而不是.NET中。是的,在.NET中throw;工作得很好。在Mono中没有,至少在我使用的版本中没有(Unity3D的Mono 2.8的自定义构建(。示例:

    static void CheckRethrow()
    {
        try
        {
            f(0);
        }
        catch (Exception ex)
        {
            Debug.LogException(ex);
        }
    }
    static void f(int i)
    {
        try
        {
            if (i > 3)
                throw new Exception("some message");
            f(++i);
        }
        catch (Exception ex)
        {
            throw;
        }
    }

输出调用堆栈:

f (Int32 i) (at Test.cs:18)
CheckRethrow() (at Test.cs:9)

正如您所看到的,在这个调用堆栈中缺少对f()的几个调用。

Mono:如何(重新)抛出异常,保留原始堆栈跟踪信息并收集本地数据

在.NET中,几乎所有异常都有一个名为InnerException的成员。这样可以有多个异常或一系列异常。

void func(...)
{
    try
    {
         ...
         func(...);
    }
    catch (Exception ex)
    {
        throw new MyOwnExceptionWithLocalData(localData, ex);
    }
}

或者,尽管我还没有测试过它,但您可以向异常添加信息,并通过不提及变量来保留它的堆栈跟踪:

void func(...)
{
    try
    {
         ...
         func(...);
    }
    catch (Exception ex)
    {
        ex.Property = value;
        throw; // Note: no variable name here, will throw last exception and preserve stack trace
    }
}

只需使用键投掷

try {
} catch (Exception ex){      
    throw;
}