未捕获异步方法中的异常

Exception in async methods is not caught

以下代码没有捕捉到我通过调用 ct.ThrowIfCancellationRequested.

抛出的 OperationCancelException
public partial class TitleWindow : Window, IAsyncInitialization
{
    public Task Initialization{get; private set;}
    CancellationTokenSource cts;

    public TitleWindow()
    {
        InitializeComponent();
        cts = new CancellationTokenSource();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        try
        {
            cts.Cancel();
            Initialization = GetCancelExceptionAsync(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Operation canceled!");
        }
    }

    public async Task GetCancelExceptionAsync(CancellationToken ct)
    {
        await Task.Delay(1000);
        ct.ThrowIfCancellationRequested();
    }
}

但是,如果我将 Window_Loaded 方法替换为以下内容(使其异步并等待异步方法的调用),则会捕获异常。

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
    try
    {
        cts.Cancel();
        await GetCancelExceptionAsync(cts.Token);
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("Operation canceled!");
    }
}

为什么我的第一种方法不起作用?异常是否没有正确传播到正确的同步上下文?

我正在尝试使用 The Asynchronous Initialization Pattern 中描述的 Stephen Clearys blog post to be able to later on await a task which was started in a constructor (and in order to make it comparable to my second example I used the (async) Window_Loaded event to await methods there right away, like suggested to me in a )。然后我想提供一个选项来取消我在构造函数中启动的异步方法,我目前被困在那里,因为异常处理没有按我预期的那样工作。

使用我的 "non-working" 代码,我可以通过将 await Initialization 放在某处的 try-catch 块中来捕获异常,但我仍然得到一个额外的未处理异常。

我如何以允许我稍后等待我的异步方法(以确保我不使用我的对象的不一致状态)并且仍然能够取消那个 long-运行 任务(当然需要 return/set 默认值)?

在您的第一个示例中,未捕获到异常,因为它不会在离开 try/catch 块之前发生。如果你想在那里抓住它,你需要像第二个例子中那样等待/await 它在那里。 如果您不等待返回的任务,该方法将继续执行并在异常实际发生之前离开 try/catch 块...

如果你想捕获异常"out of band"你也可以注册到TaskScheduler.UnobservedTaskException(如果一个任务抛出一个没有被捕获的异常就会调用这个事件)来获取所有未捕获的异常或者监视任务 Exception property. May also check out THIS 回答。

另一个线程上的任务抛出异常。

public async Task GetCancelExceptionAsync(CancellationToken ct)
        {
            try
            {
                await Task.Delay(1000);
                ct.ThrowIfCancellationRequested();
            }
            catch (Exception e)
            {
                // your Cancleation expeption
            }
        }