c# - 使用异步代码时获得有意义的堆栈跟踪

标签 c# async-await

我已经创建了一小段代码来并行运行多个异步操作(Parallel 类本身不适合异步操作)。

看起来像这样:

public static async Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
    var chunks = source.Chunk(dop);
    foreach (var chunk in chunks)
        await Task.WhenAll(chunk.Select(async s => await body(s).ContinueWith(t => ThrowError(t))));
}

private static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
    while (source.Any())
    {
        yield return source.Take(chunksize);
        source = source.Skip(chunksize);
    }
}

private static void ThrowError(Task t)
{
    if (t.IsFaulted)
    {
        if (t.Exception.InnerExceptions != null && t.Exception.InnerExceptions.Count == 1)
            throw t.Exception.InnerExceptions[0];
        else
            throw t.Exception;
    }
}

就并行运行任务而言,上述代码运行良好。但是,当抛出异常时,我确实遇到了一些问题。

就返回异常消息而言,异常捕获代码工作良好,但堆栈跟踪还有很多不足之处 - 因为它指向 ThrowError 方法,而不是最初产生异常。我可以按照自己的方式工作,找出附加的调试器出了什么问题,但如果我发布这个应用程序,我将无法使用该选项——充其量,我将记录堆栈跟踪的异常。

那么 - 有什么方法可以在运行异步任务时获得更有意义的堆栈跟踪吗?

附言。这是针对 WindowsRT 应用程序的,但我认为问题不仅限于 WindowsRT 本身......

最佳答案

So - is there any way to get a more meaningful stack trace when running async tasks?

是的,您可以使用 .NET 4.5 中引入的 ExceptionDispatchInfo.Capture 专门用于异步等待:

private static void ThrowError(Task t)
{
    if (t.IsFaulted)
    {
        Exception exception = 
            t.Exception.InnerExceptions != null && t.Exception.InnerExceptions.Count == 1 
                ? t.Exception.InnerExceptions[0] 
                : t.Exception;

        ExceptionDispatchInfo.Capture(exception).Throw();
    }
}

"You can use the ExceptionDispatchInfo object that is returned by this method at another time and possibly on another thread to rethrow the specified exception, as if the exception had flowed from this point where it was captured to the point where it is rethrown. If the exception is active when it is captured, the current stack trace information and Watson information that is contained in the exception is stored. If it is inactive, that is, if it has not been thrown, it will not have any stack trace information or Watson information."

但是,请记住,异步代码中的异常通常没有您希望的那么有意义,因为所有异常都是从编译器生成的状态机上的 MoveNext 方法内部抛出的。

关于c# - 使用异步代码时获得有意义的堆栈跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33994783/

相关文章:

c# - 如何将分数与整数相加..?

c# - UWP 等待用户与 ContentDialog 交互

javascript - 使用 JavaScript 在 SharePoint 库中创建文件夹结构

c# - 序列化时如何自动忽略没有相应构造函数参数的所有属性

c# - 如何将模型从 View 传递到局部 View ?

c# - 在 MySQL 中计算距离并在 .NET 中显示它们之间的距离

c# - 最小起订量:无法转换到界面

swift - 如何取消具有从 `async` 操作启动返回的可取消类型的 `async` 函数

asynchronous - ServiceStack 和 OrmLite 中的异步支持

python-3.x - Asyncio,由于哨兵问题,任务没有正确完成