是否可以使用Wait来捕获ContinueWith中的异常?

时间:2017-02-24 18:47:11

标签: c# .net winforms user-interface task-parallel-library

我刚刚将我的主应用程序从.NET 2.0升级到.NET 4.5,并且我试图利用C#5.0提供的更高级的语言功能。

我目前正在重新编写一些旧的异步代码例程,这些例程使用" MethodInvoker" /" AsyncCallback" (以保持UI流畅)任务

以下是旧代码遵循的模式......

void RefreshScreen()
{
  // code to prepare UI for updating
  ...
  MethodInvoker del = new MethodInvoker(LoadData);
  del.BeginInvoke(new AsyncCallback(LoadData_Callback), null);
}

void LoadData()
{
  // perform data calculations
}

void LoadData_Callback(IAsyncResult ar)
{
  AsyncResult res = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
  MethodInvoker del = (MethodInvoker)res.AsyncDelegate;
  try
  {
    del.EndInvoke(ar);  // <- throw exception if one occurred during async operation
  }
  catch (Exception E)
  {
    // handle exception
  }

  // Update the UI: if (this.InvokeRequired) {...}
}

好的 - 所以我到目前为止的基于任务的等价物: -

void RefreshScreen()
{
  // code to prepare UI for updating
  ...
  Task.Run(() => LoadData()).ContinueWith((t) => LoadData_Callback(t));
}

void LoadData()
{
  // perform data calculations
}

void LoadData_Callback(Task t)
{
  try
  {
    t.Wait(); // <- throw exception if one occurred during async operation
  }
  catch (Exception E)
  {
    // handle exception
  }

  // Update the UI: if (this.InvokeRequired) {...}
}

所以这里是我的问题......我已经阅读了很多关于使用任务进行异常处理的文章和资源,其中一些人讨论了检查&#34; task.IsCompleted等问题。 &#34;和/或&#34; task.Status &#34;,并使用 TaskContinuationOptions 分支到多个 ContinueWiths

我试图让它尽可能简单,所以只需拨打&#34; task.Wait()&#34;在一个ContinueWith方法中,在那里捕获一个Exception(根据上面的代码)还是有更好的方法来做到这一点?

非常感谢!

更新和答案

为了澄清,我应该解释原始代码在WinForms应用程序中使用,目标是在长DB操作(或任何其他长进程)期间保持UI响应,通过异步运行它们一个不同的主题。

Silas和Servy指出,自从切换到C#5.0后,我应该使用 async / 等待,所以这是我选择使用的代码类似于上面的例子......

async Task RefreshScreen()
{
  // code to prepare UI for updating
  ...
  try
  {
    await Task.Run(() => LoadData());
  }
  catch (Exception E)
  {
    // handle exception
  }
  // Update the UI: WITHOUT the need to check "this.InvokeRequired"
  return Task.FromResult(0);
}

Task LoadData()
{
  // perform data calculations
  return Task.FromResult(0);
}

此代码至少有两个好处超过&#34; MethodInvoker &#34;或&#34; 任务&#34;方法: -
(1)它更清楚了 (2)Ater从 await 返回,后续代码在UI线程上,所以没有必要用&#34; if(this.InvokeRequired){ ...} &#34; (see Stephen Cleary's blog for more information on this)。

原始问题怎么样? 是否可以使用Wait来捕获ContinueWith中的异常?

我认为这是一个没有实际意义的问题,因为 async / await 显然是要走的路,但经过进一步的研究,答案是肯定的。&#39;没问题!

1 个答案:

答案 0 :(得分:5)

您可以用以下内容替换所有内容:

public async Task LoadData()
{
  // do something DB intensive
}

public async Task HandleLoadExceptions()
{  
    try
    {
        await LoadData();
    }
    catch (Exception E)
    {
        // handle exception
    }
}