26

Task<TDerived>C# の Task はクラスであるため、明らかに aを a にキャストできませんTask<TBase>

ただし、次のことができます。

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

Task<TDerived>基本的に基礎となるタスクを指し示し、結果をキャストするインスタンスを取得するために呼び出すことができる静的タスク メソッドはありますか? 次のようなものが欲しいです:

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

そのような方法は存在しますか?この目的のためだけに非同期メソッドを使用すると、オーバーヘッドはありますか?

4

3 に答える 3

42

そのような方法は存在しますか?

いいえ。

この目的のためだけに非同期メソッドを使用すると、オーバーヘッドはありますか?

はい。しかし、それは最も簡単な解決策です。

Taskより一般的なアプローチは、などの拡張メソッドであることに注意してくださいThen。Stephen Toubがブログ投稿でこれを調査し、最近AsyncEx に組み込みました。

を使用するThenと、コードは次のようになります。

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

オーバーヘッドがわずかに少ない別のアプローチは、独自のものを作成TaskCompletionSource<TBase>し、派生結果で完了することです (TryCompleteFromCompletedTask私の AsyncEx ライブラリを使用):

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;
}
于 2013-03-20T17:07:44.720 に答える
20

そのような方法は存在しますか?この目的のためだけに非同期メソッドを使用すると、オーバーヘッドはありますか?

このための組み込みメソッドはなく、これによりオーバーヘッドが発生します。

「最も軽量な」代替手段は、 a を使用し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;
}
于 2013-03-20T17:14:33.797 に答える
1

あなたはこれを試すことができます: task.ContinueWith<TDerived>( t => (TDerived)t.Result);

于 2015-08-04T12:19:04.000 に答える