在UI构造函数中使用Task.Run()时处理异常

本文关键字:处理 异常 Run Task 构造函数 UI | 更新日期: 2023-09-27 18:06:51

我有一个这样调用Task.Run()的构造函数:

public MyPage() {
    Task.Run(() => {
        MyHeavyCpuMethod();
    });
}

这里,MyPage()是一个UI组件的构造函数,我不希望MyHeavyCpuMethod()在我的UI线程上运行,所以我用Task.Run()卸载它,因为我并不真正关心MyHeavyCpuMethod()何时完成。

然而,这样,如果MyHeavyCpuMethod()抛出,我不能处理在返回的任务中的异常。

在这种情况下我如何处理错误?

在UI构造函数中使用Task.Run()时处理异常

一个选择是使用async/await…它不能与构造函数一起工作,但是可以在静态方法中工作:

public static async Task<MyPage> CreateInstance()
{
    await Task.Run(...);
    // Anything else asynchronous you want to use
    return new MyPage();
}
然后假设你在异步方法中使用 this,你可以使用:
MyPage page = await MyPage.CreateInstance();

这样,如果cpu绑定任务失败,您甚至无法调用构造函数。在这里,构造函数调用本身被期望是快速的,因为放在UI线程上(如您所愿)。

另一种方法是,您可以将Task.Run返回的任务存储为页面中的字段,然后等待后期构造…使用正常的异步异常处理方法

添加一个ContinueWith,只有当Task没有运行到完成(抛出异常)时才会触发:

Task.Run(() => MyHeavyCpuMethod())
    .ContinueWith(task => { /* some action */  }, TaskContinuationOptions.OnlyOnFaulted);

你的第二个任务也不会在UI线程上运行,根据文档:

创建一个延续,在目标任务完成时异步执行。

您可以使用一个虚拟方法来尝试:

Task.Run(() =>
{
      throw new Exception();
}).ContinueWith(t =>
{
    Invoke((MethodInvoker)(() => MessageBox.Show("ERROR")));
}, TaskContinuationOptions.OnlyOnFaulted);