简体   繁体   中英

Stack frames visible in Visual Studio 2017 Call Stack are missing in System.Diagnostics.StackTrace when resuming C# async method

I have the following simple C# code snippet that uses asyc methods:

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();
    }
}

I place breakpoint on "return 42" statement and observe both Visual Studio Call Stack and the StackTrace obtained from System.Diagnostics.StackTrace(). There are some frames visible in VS Call Stack window that are not presented in the StackTrace as can be seen in the following picture: StackTrace is missing frames from VS Call Stack window

Is there a way to get the stack trace using System.Diagnostics.StackTrace exactly as it is observed in Visual Studio Call Stack window?

Well, if you think about what a stacktrace is, it is literaly a stack of called methods. Where the deepest method resides on top of the stack. If you would consider the following program, Main calls first, first calls second, and second calls third.

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

}

When you are inside the Third method, your stack will look like this (left being the top of the stack):

Third - Second - First - Main

Then when Third is completed, Third is popped off the stack and the trace looks like this:

Second - First - Main

etc. etc.

Now this is easy to follow when no asynchronous code is involved. So let's see what is happening in your example:

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.");
}

When you put a breakpoint in the first line of the First method, the callstack is similar as above, because the code executed synchronously up to that point. However, the method actually returns at the call to await Task.Delay , popping the First method off the stack. The only way the third line can be accessed after that is if the framework creates a 'continuation' at the third line. Now it may be clear that this continuation has to be invoked by something other than our own code, and that is why the callstack contains all these strange methods.

So you cannot get a callstack containing only your code, because it no longer exists, but in the Visual Studio settings, you may enable Just My Code . That may look like this when you break on line 3 of the First method in the last example. Not exactly what you are looking for, but close.

(Screenshot from VSCode)

异步callstack截图

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM