Кадры стека, видимые в стеке вызовов Visual Studio 2017, отсутствуют в System.Diagnostics.StackTrace при возобновлении асинхронного метода C # - PullRequest
3 голосов
/ 20 марта 2019

У меня есть следующий простой фрагмент кода 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, так и StackTrace, полученный из System.Diagnostics.Трассировки стека().В окне VS Call Stack есть некоторые кадры, которые не представлены в StackTrace, как видно на следующем рисунке: В StackTrace отсутствуют кадры из окна VS Call Stack

Есть лиспособ получить трассировку стека с помощью System.Diagnostics.StackTrace в точности так, как это наблюдается в окне Visual Studio Call Stack?

1 Ответ

0 голосов
/ 20 марта 2019

Ну, если вы подумаете о том, что такое трассировка стека, это буквально стек вызванных методов.Где самый глубокий метод находится на вершине стека.Если вы рассмотрите следующую программу, 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 - 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, стек вызовов аналогичен описанному выше, поскольку код, выполняемый синхронно до этоготочка.Однако метод на самом деле возвращает при вызове await Task.Delay, выталкивая метод First из стека.Единственный способ получить доступ к третьей строке после этого - это если фреймворк создает «продолжение» в третьей строке.Теперь может быть ясно, что это продолжение должно вызываться чем-то отличным от нашего собственного кода, и именно поэтому callstack содержит все эти странные методы.

Таким образом, вы не можете получить callstack, содержащий только ваш код, потому чтоон больше не существует, но в настройках Visual Studio вы можете включить Just My Code .Это может выглядеть так, когда вы разбиваете строку 3 метода First в последнем примере.Не совсем то, что вы ищете, но близко.

(Скриншот из VSCode)

Async callstack screenshot

...