Подтвердить что ты не робот

Ожидание с .NET 4.0: значимые трассировки стека

У меня есть проект приложения консоли С# с использованием .NET 4.0 с установленным пакетом Microsoft.Bcl.Async. Я использую этот код:

internal class Program
{
    private static void Main(string[] args)
    {
        Foo().Wait();
    }

    static void Log(Exception ex)
    {

    }

    private static async Task Foo()
    {
        try
        {
            await DoSomething();
        }
        catch (Exception ex)
        {
            Log(ex);
        }
    }

    private static async Task DoSomething()
    {
        throw new DivideByZeroException();
    }
}

Если я поставлю точку останова внутри метода журнала, я получаю исключение DivideByZero, но трассировка стека, которую я вижу, это:

at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.GetResult()
at AsyncStacks.Program.<Foo>d__0.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 25

Эта трассировка стека находится рядом с бесполезной, поскольку она не говорит мне, где действительно было выбрано исключение.

Если я изменю свой проект на целевой .NET 4.5, я получаю более полезное исключение:

at AsyncStacks.Program.<DoSomething>d__3.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 35
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at AsyncStacks.Program.<Foo>d__0.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 25

Как я могу получить полезную трассировку стека из проекта .NET 4.0 при использовании await?

Обновление

"Старый" AsyncTargetingPack делает гораздо лучшую трассировку стека. Вопрос, похоже, был введен в "новый" Microsoft.Bcl.Async.

4b9b3361

Ответ 1

Изменение Foo на это означает, что получится лучший результат:

private static async Task Foo()
{
    await DoSomething().ContinueWith(t => Log(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
}

Обновление. Однако недостатком является то, что вы должны использовать один и тот же .ContinueWith каждый раз, когда используете ключевое слово await. Если вы ожидаете чего-то, что также ожидает, вам также нужно .ContinueWith.