TaskCompletionSource用法

时间:2015-04-22 05:52:24

标签: c# async-await taskcompletionsource

如果完成源被取消,我会在结果变量中收到什么?

async void SomeMethod()
{
   .....
   Run();
   var result = await GetResult();
   .....
}

Task<SomeResult> GetResult()
{
    return myCompletionSource.Task;
}

TaskCompletionSource myCompletionSource;

void Run()
{
     myCompletionSource= new TaskCompletionSource();
     TriggerSomeLongLastingLogicWhichWillCallCallBackBelow();

}

void SomeCallback()
{
     if (someCondition)
     {
         myCompletionSource.SetResult(<someResult>);
     }
     else
     {
         myCompletionSource.SetCancelled();
     }
}

我不太确定这种方法是否正确。

  1. 换句话说,依靠任务状态而不是使用状态变量为“someresult”创建包装器是一种好习惯吗?
  2. 如何处理已取消的任务?我不喜欢回调,也不喜欢使用ContinueWith解决方案,我可以在其中分析任务状态。

1 个答案:

答案 0 :(得分:4)

  

如果完成源被取消,我会在结果变量中收到什么?

在等待已取消的任务时,您的代码将抛出OperationCancelledException。所以结果变量永远不会被设置。

您可以使用try/catch块处理异常:

async Task SomeMethod()
{
   try
   {
       .....
       Run();
       var result = await GetResult();
   }
   catch(OperationCancelledException)
   {
       // handle cancelled operation
   }
}

此外,SomeMethod应该返回Taskvoid返回async方法通常仅适用于事件处理程序,因为它们必须返回void。我在博客中简要介绍here

一般情况下,如果您希望操作可取消,则传入操作必须检查的CancellationToken并传递给其启动的其他操作。所以你将它一直传递到链中并进入你的回调。

您还可以使用CancellationToken注册一个回调,以便在取消令牌时取消TaskCompletionSource,这样您就不需要在方法中执行此操作。

void Run()
{   
     var cts = new CancellationTokenSource();
     var myCompletionSource= new TaskCompletionSource();
     cts.Token.Register(() => myCompletionSource.SetCancelled());

     TriggerSomeLongLastingLogicWhichWillCallCallBackBelow(cts.Token);         
}

void SomeCallback(CancellationToken token)
{       
     // do some work
     ....

     token.ThrowIfCancellationRequested();

     if (someCondition)
     {
         myCompletionSource.SetResult(<someResult>);
     }
     else
     {
         myCompletionSource.SetException(new Exception("error occcured"));
     }
}