未捕获异步方法中的异常 [英] Exception in async methods is not caught
问题描述
以下代码无法捕获我通过调用ct.ThrowIfCancellationRequested
引发的OperationCancelException.
The following code does not catch my OperationCancelException which is thrown by calling 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();
}
}
但是,如果我将我的Window_Loaded
方法替换为以下内容(使其异步并等待异步方法的调用),则会捕获异常.
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.
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?
我正在尝试使用 Stephen中所述的The Asynchronous Initialization Pattern
Clearys博客文章,以便稍后可以等待在构造函数中启动的任务(并且为了使其与我的第二个示例具有可比性,我使用了(async
)Window_Loaded
事件来等待在那里的方法就像在上一个问题).然后,我想提供一个选项,以取消在构造函数中启动的异步方法,该方法由于不如预期的那样无法正常工作,而目前仍停留在该方法中.
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). 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.
使用我的非工作"代码,可以通过将await Initialization
放在try-catch块中的某个地方来捕获异常,但是我仍然会收到其他未处理的异常.
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.
如何以一种允许我稍后等待异步方法的方式实现此方法(以确保我不会处理对象的不一致状态),并且仍然能够取消该长期运行的Task(当然需要返回/设置默认值)?
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)?
推荐答案
在您的第一个示例中,未捕获到异常,因为在离开try/catch
块之前不会发生该异常.如果要在那里捕获它,则需要像在第二个示例中一样完全在其中等待/await
.
如果您不等待返回的任务,则该方法将继续执行并在实际发生异常之前离开try/catch
块...
In your first example the exception is not caught because it does not occure before leaving the try/catch
block. If you want to catch it there you need to wait/await
it there exactly like you do in the second example.
If you do not await the returned task the method continues execution and leaves the try/catch
block before the exception actually occures...
如果要带外"捕获异常,还可以注册到TaskScheduler.UnobservedTaskException
(如果任务抛出了一个未被捕获的异常,则调用此事件)以获取所有未捕获的异常或监视任务 Exception
属性.也可以查看这答案.
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. May also check out THIS answer.
这篇关于未捕获异步方法中的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!