简体   繁体   English

没有TaskCompletionSource的任务链?

[英]Task chaining without TaskCompletionSource?

I'm converting some async/await code to chained tasks, so I can use it in the released framework. 我正在将一些异步/等待代码转换为链接的任务,因此可以在发布的框架中使用它。 The await code looks like this 等待代码如下所示

public async Task<TraumMessage> Get() {
  var message = await Invoke("GET");
  var memorized = await message.Memorize();
  return memorized;
}

where 哪里

Task<TraumMessage> Invoke(string verb) {}
Task<TraumMessage> Memorize() {}

I was hoping to chain Invoke and Memorize to return the task produced by Memorize , but that results in a Task<Task<TraumMessage> . 我希望链接InvokeMemorize以返回由Memorize产生的任务,但这导致Task<Task<TraumMessage> The solution i've ended up is a TaskCompletionSource<TraumMessage> as my signal: 我最终的解决方案是一个TaskCompletionSource<TraumMessage>作为我的信号:

public Task<TraumMessage> Get() {
  var completion = new TaskCompletionSource<TraumMessage>();
  Invoke("GET").ContinueWith( t1 => {
     if(t1.IsFaulted) {
       completion.SetException(t1.Exception);
       return;
     }
     t1.Result.Memorize().ContinueWith( t2 => {
       if(t2.IsFaulted) {
         completion.SetException(t2.Exception);
         return;
       }
       completion.SetResult(t2.Result);
     });
  });
  return completion.Task;
}

Is there a way to accomplish this without the TaskCompletionSource ? 没有TaskCompletionSource有没有办法做到这TaskCompletionSource

Yes, the framework comes with a handy Unwrap() extension method for exactly what you want. 是的,该框架附带了一个方便的Unwrap()扩展方法,可以完全满足您的需求。

Invoke("GET").ContinueWith( t => t.Result.Memorize() ).Unwrap();

If you're doing cancellation then you'll need to pass cancel tokens into the appropriate places, obviously. 如果您要进行取消,那么显然需要将取消令牌传递到适当的位置。

I think that's pretty much the only way to accomplish what you want. 我认为这几乎是实现所需目标的唯一方法。 Chaining disparate Tasks together isn't supported by the continuation APIs, so you have to resort to using a TaskCompletionSource like you have to coordinate the work. 连续API不支持将完全不同的任务链接在一起,因此您必须像使用工作协调一样使用TaskCompletionSource

I don't have the Async CTP installed on this machine, but why don't you take a look at the code with a decompiler (or ILDASM if you know how to read IL) to see what it's doing. 我没有在这台机器上安装Async CTP,但是为什么不使用反编译器(或者ILDASM,如果您知道如何读取IL)来查看代码,以查看其工作情况。 I bet it does something very similar to your TCS code under the covers. 我敢打赌,它的功能与您幕后的TCS代码非常相似。

You can use attached child tasks. 您可以使用附加的子任务。 The parent task will only transition into the completed status when all child tasks are complete. 仅当所有子任务完成后,父任务才会转换为完成状态。 Exceptions are propagated to the parent task. 异常会传播到父任务。 You will need a result holder, as the result will be assigned after the parent task's delegate has finished, but will be set when the parent tasks continuations are run. 您将需要一个结果持有者,因为结果将在父任务的委托完成分配,但将在运行父任务继续时设置。

Like this: 像这样:

public class Holder<T> where T: class
{
   public T Value { get; set; }
}

public Task<Holder<TraumMessage>> Get() {
  var invokeTask = Invoke("GET");
  var result = invokeTask.ContinueWith<Holder<TraumMessage>>(t1 => {
    var holder = new Holder<TraumMessage>();
    var memorizeTask = t1.Result.Memorize();
    memorizeTask.ContinueWith(t2 => {
      holder.Value = t2.Result;
    }, TaskContinuationOptions.AttachedToParent);
    return holder;
  });
  return result;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM