2017-09-16 6 views
0

私は、RxJS(ちょうど標準のObservable)にコールドオブザーバブルオブジェクトのようなものを実装する必要があります。コンストラクタ(new Task())を使って自分自身を作成し​​たタスクの中で非同期メソッドを呼び出す必要があります。これを実装する必要があるのは、非同期コードを実行する前に、私のプロジェクトに特有のものをいくつか実行したいからです。だから私は少し手作業で始めることができるまだ開始されていないタスクを受け取りたい。手動で作成されたタスクの中で非同期メソッドを呼び出す方法は?

これまでのところ私は次の決定に来て、私の驚きにはうまくいかない!

class Program 
{ 
    static void Main(string[] args) 
    { 
     var task1 = CallApi(() => t.Go()); 
     var task2 = CallApi2(() => t.Go()); 


     task1.Start(); 
     task2.Start(); 

    } 



    public static Task<T> CallApi<T>(Func<Task<T>> function) 
    { 
     if (function == null) 
     { 
      throw new ArgumentNullException(nameof(function)); 
     } 


     return new Task<Task<T>>(async() => 
     { 
      return await function(); 
     }).Unwrap(); 


    } 

    public static Task<T> CallApi2<T>(Func<Task<T>> function) 
    { 
     if (function == null) 
     { 
      throw new ArgumentNullException(nameof(function)); 
     } 

     var tcs = new TaskCompletionSource<T>(); 

     var resultTask = new Task<Task<T>>(() => 
     { 
      var t = function(); 

      t.ContinueWith(
       task => { 
        tcs.SetResult(task.Result); 
       }, 
       TaskContinuationOptions.OnlyOnRanToCompletion 
      ); 

      t.ContinueWith(
       task => { 
        tcs.SetCanceled(); 
       }, 
       TaskContinuationOptions.OnlyOnCanceled 
      ); 

      t.ContinueWith(
       task => { 
        tcs.SetException(task.Exception); 

       }, 
       TaskContinuationOptions.OnlyOnFaulted 
      ); 
      return tcs.Task; 
     }); 

     return resultTask.Unwrap(); 

    } 
} 

UnwrapまたはTaskCompletionSourceを呼び出すと、WaitingForActivation状態のタスクが作成されるようです。そして、この状態のタスクでStartメソッドを呼び出すと、私は例外であると言っています。

約束事スタイルのタスクではStartを呼び出すことはできません。

.NETは特別な種類のタスク(約束事のタスク)を区別している可能性が非常に高いです。要約すると

は私の質問は以下のとおりです。

  1. これらの約束スタイルのタスクが何を意味するのですか?

  2. 私は何をしたいのですか?

+0

アンラップは、あなたが思うとは思いません。コールドタスクを開始することはできません.Unwrap()コールの後に参照を失いました。この関数は単純に 'public static async Task Unwrap(this Task >タスク){return await task; } '内部の' awaitタスク 'は、あなたがその外部タスクを開始する方法を失ったため決して完了しません。 –

+0

@ScottChamberlain私はこのように考えていません。だから私はUnwrapによって返されたタスクでStartを呼び出そうとしたのです。 – Dobby007

答えて

2

約束スタイルのタスクはスレッドに基づいてされていないタスクです、彼らはTaskCompletionSource「イベント」のためにタスクを受信するにはSetResultSetCanceledまたは

SetExceptionを呼び出す行為があり、イベントに基づいていますまだ起動していないものがあります。これは少し後で手動で起動することができます。単にFunc<Task<T>>を保持して、後でそのタスクを起動する機能を評価します。これは非常に簡単に行うことができます。

public void Example() 
    { 
     Func<Task<T>> func1 =() => t.Go(); 

     //Do other work 

     Task<T> task1 = func1(); //t.Go() is not called until this point then the task starts. 

    } 
+0

これは私が現時点で入手したものです。私はあなたの例のように代理人を使用しましたが、確かにそれは動作します。私はそれを呼び出すとタスクを開始します。しかし、私は、タスクだけを使用する場合と全く同じことをしたい。それは可能ではありませんか? – Dobby007

+0

コールドタスクはコンストラクタに渡すデリゲートを保持しているだけで、デリゲートを実行するために余分なスレッドを使います。それが、タスクのコンストラクタが受け入れる唯一のものであるため、「代理人なしで」これを行う方法はありません。不必要なスレッドを使用せず、デリゲートを自分で実行するだけで、パフォーマンスを自分で節約できます。 –

+0

あなたは私の質問でそれをやろうとしているのを見ることができます。デリゲートをCallApiメソッドに渡すだけで、 "コールド"タスクが作成されます。しかし、この冷たい仕事は全く始まっていません。私が言った例外をスローします。あなたはパフォーマンスの質問に関係なく私にそれをする方法を提供できますか? – Dobby007

関連する問題