在恢复C#异步方法时,System.Diagnostics.StackTrace中缺少Visual Studio 2017调用堆栈中可见的堆栈帧

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在恢复C#异步方法时,System.Diagnostics.StackTrace中缺少Visual Studio 2017调用堆栈中可见的堆栈帧相关的知识,希望对你有一定的参考价值。

我有以下使用asyc方法的简单C#代码片段:

class SUT
{
    public async Task<int> GetValue()
    {
        await Task.Delay(1000);
        return 42;
    }
}

class Program
{
    static async Task<int> CallAsync()
    {
        SUT sut = new SUT();
        int result = await sut.GetValue();
        return result;
    }
    static void Main(string[] args)
    {
        CallAsync().GetAwaiter().GetResult();
    }
}

我将断点放在“return 42”语句中,并观察Visual Studio Call Stack和从System.Diagnostics.StackTrace()获得的StackTrace。在VS Call Stack窗口中可以看到一些未在StackTrace中显示的帧,如下图所示:StackTrace is missing frames from VS Call Stack window

有没有办法使用System.Diagnostics.StackTrace完全按照在Visual Studio调用堆栈窗口中观察到的方式获取堆栈跟踪?

答案

好吧,如果你考虑堆栈跟踪是什么,它就是一堆被称为方法的文件。最深层的方法位于堆栈顶部。如果你考虑以下程序,Main调用第一个,第一个调用第二个,第二个调用第三个。

class Program
{
    static void Main(string[] args) => First();
    static void First() => Second();
    static void Second() => Third();
    static void Third() => Console.WriteLine("Third method.");

}

当你进入Third方法时,你的堆栈将如下所示(左边是堆栈的顶部):

Third - Second - First - Main

然后当第三个完成时,第三个从堆栈中弹出,跟踪如下所示:

Second - First - Main

等等等等

现在,当没有涉及异步代码时,这很容易理解。那么让我们看看你的例子中发生了什么:

static void Main(string[] args) => First().Wait();

static async Task First()
{
    Console.WriteLine("First method starting");
    await Task.Delay(1000);
    Console.WriteLine("First method finishing.");
}

当你在First方法的第一行中放置一个断点时,callstack与上面类似,因为代码同步执行到那一点。但是,该方法实际上在调用await Task.Delay时返回,从堆栈中弹出First方法。在此之后可以访问第三行的唯一方法是框架在第三行创建“延续”。现在可能很清楚,这个延续必须由我们自己的代码以外的东西调用,这就是callstack包含所有这些奇怪方法的原因。

因此,您无法获得仅包含代码的callstack,因为它不再存在,但在Visual Studio设置中,您可以启用Just My Code。当您在上一个示例中的First方法的第3行中断时,这可能看起来像这样。不完全是你想要的,但接近。

(来自VSCode的截图)

Async callstack screenshot

以上是关于在恢复C#异步方法时,System.Diagnostics.StackTrace中缺少Visual Studio 2017调用堆栈中可见的堆栈帧的主要内容,如果未能解决你的问题,请参考以下文章

C#执行EXE程序

c#使用泛型方法,在运行时已知类型的异步方法

电脑C盘文件丢失的常见原因及恢复方法

自动挂钩到 Activity 生命周期方法的异步任务库

使用HttpClient异步方法时内存泄漏c#

C#8.0: 在 LINQ 中支持异步的 IAsyncEnumerable