C# async / await unobserved exception

自作多情 提交于 2020-01-21 12:47:22

问题


I'm trying to understand why the following code:

async void Handle_Clicked(object sender, System.EventArgs e)
{
    try
    {
        await CrashAsync("aaa");
    }
    catch (Exception exception)
    {
        Log($"observed exception");

        Log($"Exception: {exception.Message}");
    }
}

private async Task CrashAsync(string title)
{
    Log($"CrashAsync ({title}) - before");

    await Task.Delay(1000);

    throw new Exception($"CrashAsync ({title})");

    Log($"CrashAsync ({title}) - after");
}

produces the expected result:

thread #1: CrashAsync (aaa) - before

thread #1: observed exception

thread #1: Exception: CrashAsync (aaa)

but if I change it to this one:

async void Handle_Clicked(object sender, System.EventArgs e)
{
    try
    {
        await CrashAsync("aaa").ContinueWith(async (t) =>
        {                   
            await CrashAsync("bbb");
        },TaskContinuationOptions.OnlyOnRanToCompletion);
    }
    catch (Exception exception)
    {
        Log($"observed exception");

        Log($"Exception: {exception.Message}");
    }
}

I get the following output:

thread #1: CrashAsync (aaa) - before

thread #1: observed exception

thread #1: Exception: A task was canceled.

thread #2: unobserved exception

thread #2: System.Exception: CrashAsync (aaa) at AsyncTest.AsyncTestPage+c__async3.MoveNext () [0x000ad] in /Users/johndoe/Development/Xamarin/AsyncTest/AsyncTest/AsyncTestPage.xaml.cs:82

where:

TaskScheduler.UnobservedTaskException += (sender, e) =>
{
    Debug.WriteLine($"thread #{Environment.CurrentManagedThreadId}: unobserved exception");

    foreach (var exception in e.Exception.Flatten().InnerExceptions)
    {
        Debug.WriteLine($"thread #{Environment.CurrentManagedThreadId}: {exception}");
    }
};

The continuation condition is not satisfied so the ContinueWith task is cancelled, but why do I have unobserved exception?


回答1:


You await Task returned by ContinueWith, so you observe exception related to this Task - that it was cancelled (TaskCanceledException). But you don't observe original exception thrown by CrashAsync (so "CrashAsync aaa") exception, hence the behavior you observe.

Here is sample code to get more understanding:

static async void Test() {
    var originalTask = CrashAsync("aaa");
    var onSuccess = originalTask.ContinueWith(async (t) =>
    {
        await CrashAsync("bbb");
    }, TaskContinuationOptions.OnlyOnRanToCompletion);
    var onFault = originalTask.ContinueWith(t => {                    
        Log("Observed original exception: " + t.Exception.InnerExceptions[0].Message);
    }, TaskContinuationOptions.OnlyOnFaulted);
}

So in short - just await your task and catch exception if any. You don't need to use ContinueWith at all, because if you use await - the rest of the method is already a continuation.



来源:https://stackoverflow.com/questions/39915703/c-sharp-async-await-unobserved-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!