c# async / await未观察异常

本文关键字:观察 异常 await async | 更新日期: 2023-09-27 18:12:11

我想理解为什么下面的代码:

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

产生预期的结果:

thread #1: CrashAsync (aaa) - before

线程#1:观察到异常

线程#1:Exception: CrashAsync (aaa)

但是如果我把它改成这个

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

得到以下输出:

thread #1: CrashAsync (aaa) - before

线程#1:观察到异常

线程#1:Exception: A task was cancelled .

线程#2:unobserved exception

线程#2:System。异常:CrashAsync (aaa)在AsyncTest.AsyncTestPage + c__async3。MoveNext () [0x000ad] in/Users/johndoe/Development/Xamarin/AsyncTest/AsyncTest/asynctestpage . example .cs:82

地点:

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

连续性条件不满足,因此ContinueWith任务被取消,但为什么我有未观察到的异常?

c# async / await未观察异常

您等待ContinueWith返回的Task,因此您观察到与此Task相关的异常-它被取消(TaskCanceledException)。但是你没有观察到CrashAsync抛出的原始异常(所以"CrashAsync aaa")异常,因此你观察到的行为。

下面是示例代码,以获得更多的理解:
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);
}

所以简而言之-等待你的任务并捕获异常(如果有的话)。您根本不需要使用ContinueWith,因为如果您使用await -方法的其余部分已经是一个延续