没有 TaskCompletionSource 的任务链?

发布于 2024-11-27 06:25:11 字数 1143 浏览 1 评论 0原文

我正在将一些异步/等待代码转换为链接任务,以便我可以在已发布的框架中使用它。等待代码如下所示

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

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

我希望链接 InvokeMemorize 以返回由 Memorize 生成的任务,但这会导致 <代码>任务<任务。我最终得到的解决方案是使用 TaskCompletionSource 作为我的信号:

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;
}

有没有办法在没有 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>. The solution i've ended up is a TaskCompletionSource<TraumMessage> as my signal:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

殊姿 2024-12-04 06:25:11

是的,该框架附带了一个方便的 Unwrap() 扩展方法,可以满足您的需求。

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

如果您要取消,那么显然您需要将取消令牌传递到适当的位置。

Yes, the framework comes with a handy Unwrap() extension method for exactly what you want.

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.

浮世清欢 2024-12-04 06:25:11

我认为这几乎是实现你想要的目标的唯一方法。延续 API 不支持将不同的任务链接在一起,因此您必须使用 TaskCompletionSource 就像协调工作一样。

我没有在这台机器上安装 Async CTP,但是为什么你不使用反编译器(或者 ILDASM,如果你知道如何阅读 IL)来查看代码,看看它在做什么。我敢打赌它在幕后所做的事情与你的 TCS 代码非常相似。

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.

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. I bet it does something very similar to your TCS code under the covers.

溺渁∝ 2024-12-04 06:25:11

您可以使用附加的子任务。只有当所有子任务都完成时,父任务才会转换为已完成状态。异常会传播到父任务。
您将需要一个结果持有者,因为结果将在父任务的委托完成后分配,但会在父任务延续运行时设置。

像这样:

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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文