繁体   English   中英

如何转换任务<TDerived>到一个任务<TBase> ?

[英]How to convert a Task<TDerived> to a Task<TBase>?

由于 C# 的 Task 是一个类,您显然不能将Task<TDerived>转换为Task<TBase>

但是,您可以这样做:

public async Task<TBase> Run() {
    return await MethodThatReturnsDerivedTask();
}

是否有我可以调用的静态任务方法来获取Task<TDerived>实例,该实例本质上只是指向底层任务并转换结果? 我想要类似的东西:

public Task<TBase> Run() {
    return Task.FromDerived(MethodThatReturnsDerivedTask());
}

有这样的方法吗? 仅为此目的使用异步方法是否有任何开销?

有这样的方法吗?

不。

仅为此目的使用异步方法是否有任何开销?

是的。 但这是最简单的解决方案。

请注意,更通用的方法是Task的扩展方法,例如Then Stephen Toub 在一篇博客文章中对此进行了探讨,我最近将其合并到 AsyncEx 中

使用Then ,您的代码将如下所示:

public Task<TBase> Run()
{
  return MethodThatReturnsDerivedTask().Then(x => (TBase)x);
}

另一种开销稍少的方法是创建自己的TaskCompletionSource<TBase>并使用派生结果完成它(在我的 AsyncEx 库中使用TryCompleteFromCompletedTask ):

public Task<TBase> Run()
{
  var tcs = new TaskCompletionSource<TBase>();
  MethodThatReturnsDerivedTask().ContinueWith(
      t => tcs.TryCompleteFromCompletedTask(t),
      TaskContinuationOptions.ExecuteSynchronously);
  return tcs.Task;
}

或者(如果您不想依赖 AsyncEx):

public Task<TBase> Run()
{
  var tcs = new TaskCompletionSource<TBase>();
  MethodThatReturnsDerivedTask().ContinueWith(t =>
  {
    if (t.IsFaulted)
      tcs.TrySetException(t.Exception.InnerExceptions);
    else if (t.IsCanceled)
      tcs.TrySetCanceled();
    else
      tcs.TrySetResult(t.Result);
  }, TaskContinuationOptions.ExecuteSynchronously);
  return tcs.Task;
}

有这样的方法吗? 仅为此目的使用异步方法是否有任何开销?

没有为此的内置方法,这确实会导致开销。

“最轻量级”的替代方法是使用TaskCompletionSource<T>为此创建一个新任务。 这可以通过像这样的扩展方法来完成:

static Task<TBase> FromDerived<TBase, TDerived>(this Task<TDerived> task) where TDerived : TBase
{
     var tcs = new TaskCompletionSource<TBase>();

     task.ContinueWith(t => tcs.SetResult(t.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
     task.ContinueWith(t => tcs.SetException(t.Exception.InnerExceptions), TaskContinuationOptions.OnlyOnFaulted);
     task.ContinueWith(t => tcs.SetCanceled(), TaskContinuationOptions.OnlyOnCanceled);

     return tcs.Task;
}

你可以试试这个: task.ContinueWith<TDerived>( t => (TDerived)t.Result);

暂无
暂无

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

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