简体   繁体   English

未捕获异步方法中的异常

[英]Exception in async methods is not caught

The following code does not catch my OperationCancelException which is thrown by calling ct.ThrowIfCancellationRequested . 以下代码无法捕获我通过调用ct.ThrowIfCancellationRequested引发的ct.ThrowIfCancellationRequested

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

However if i replace my Window_Loaded method with the following (making it async and await the call of my async method), the exception gets caught. 但是,如果我用以下代码替换Window_Loaded方法(使其异步并等待异步方法的调用),则会捕获异常。

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

Why is my first approach not working? 为什么我的第一种方法不起作用? Is the exception not properly propagated to the correct synchronization context? 异常是否没有正确传播到正确的同步上下文?

I was trying to use The Asynchronous Initialization Pattern described in 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 previous question ). 我试图使用Stephen Clearys博客文章中描述The Asynchronous Initialization Pattern ,以便稍后等待在构造函数中启动的任务(并且为了使其与第二个示例具有可比性,我使用了( asyncWindow_Loaded事件马上等待那里的方法,例如上一个问题中向我建议的方法)。 Then I wanted to provide an option to cancel the async method that I started in the constructor, where i am currently stuck because the exception handling does not work as I expected. 然后,我想提供一个取消在构造函数中启动的异步方法的选项,由于异常处理无法按预期工作,因此我目前仍停留在该方法中。

With my "non-working" code, I can catch the exception by putting await Initialization in a try-catch block somewhere, but I still get an additional unhandled exception. 使用我的“非工作”代码,我可以通过在某个地方的try-catch块中放置一个“ await Initialization ”来捕获该异常,但是我仍然会收到一个额外的未处理异常。

How do I implement this in a way that allows me to await my async method later on (to ensure that I do not work with an inconsistent state of my object) and still being able to cancel that long-running Task (which would of course need to return/set default values)? 如何以一种允许我以后等待异步方法的方式实现此方法(以确保我不会处理对象的不一致状态),并且仍然能够取消该长时间运行的Task(当然,需要返回/设置默认值)?

In your first example the exception is not caught because it does not occure before leaving the try/catch block. 在第一个示例中,未捕获到异常,因为在离开try/catch块之前不会发生该异常。 If you want to catch it there you need to wait/ await it there exactly like you do in the second example. 如果要在那里捕获它,则需要像在第二个示例中那样完全在这里等待/ await If you do not await the returned task the method continues execution and leaves the try/catch block before the exception actually occures... 如果您不等待返回的任务,该方法将继续执行并在实际发生异常之前离开try/catch块。

If you want to catch the exception "out of band" you can also register to TaskScheduler.UnobservedTaskException (this event is called if a task is throwing an exception which is nowhere caught) to get all uncaught exceptions or monitor the tasks Exception property. 如果要“带外”捕获异常,还可以注册TaskScheduler.UnobservedTaskException (如果任务抛出了一个未捕获的异常,则调用此事件)以获取所有未捕获的异常或监视task Exception属性。 May also check out THIS answer. 也可以查看答案。

Exeption is thrown in the task on another thread. Exeption被抛出另一个线程中的任务。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM