未捕获异步方法中的异常
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
}
}
以下代码没有捕捉到我通过调用 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
方法替换为以下内容(使其异步并等待异步方法的调用),则会捕获异常。
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
}
}