彼らはあなたのコールバックを笑うか、非同期/「貧しい人々のために」待つ

.NET 4.0にプロジェクトがあり、コールバックの「麺」にうんざりしていませんか? プロジェクトでasync / awaitを使用しますが、チームリーダーはプラットフォームを変更したことに対する天罰を脅かしていますか? フレームワークとスタジオにパッチをインストールすることが許容できるソリューションである場合、 ここにあります。 そうでない場合は、別の解決策があります。





グルの場合:yield'ahのコルーチン内



理論のビット


Asyncメソッドは、待機ごとに終了するコルーチンであり、待機が完了するとこの時点から復元されます(作成者は、実行が常にawaitによって中断されるわけではなく、タスクインスタンスだけでなく「期待」できることを知っています)。 したがって、サブネットの2番目のバージョンから開始すると、yieldキーワードを使用してコルーチンを簡単に作成できます。 このツールを使用します。



コンセプト


C#5.0のように記述したいのですが、同時に言語拡張機能をインストールしないでください。 残念ながら、これは機能しません。 しかし、そのようなオプションがあります:

private IEnumerable Login(...) { // ... // get user id, if not specified if (string.IsNullOrEmpty(uid)) { var getUserIdTask = lient.GetUserId(...); yield return getUserIdTask; // await uid= getUserIdTask.Result.uid; } // login var loginTask = lient.Login(...); yield return loginTask; // await var sessionId = loginTask.Result.SessionId; // getting user's profile var getUserInfoTask = lient.GetUserInfo(...); yield return getUserInfoTask; // await var userInfo = getUserInfoTask.Result; // ... yield return userInfo; // return }
      
      





yield returnを介して返され、Taskの継承者ではないものはすべて、非同期メソッドの実行の結果と見なされます。



実装


コードはこちらです。

操作のメカニズムは簡単です:

  1. ルートタスクを作成して呼び出し元に返す
  2. イテレーターを回転させる
  3. タスクが戻った場合、ContinueWithを介してステップ2に移行して完了するまで待ちます
  4. エラーが返された場合、馬タスクの例外をスローします
  5. 値が返された場合、指定された結果でタスクTaskを完了します
  6. イテレータが終了したら、タスクTaskを標準結果で完了します


完了のすべてのバリアントでは、反復子でDisposeが呼び出されます。これにより、使用中のリソースが解放され、try / finallyブロックが使用されます。



FromIteratorメソッドを呼び出すことにより、新しい非同期タスクを開始できます。

 private IEnumerable Login(...) { ... } Task loginTask = TaskUtils.FromIterator(this.Login(...)); //     Task<UserInfo> loginTask = TaskUtils.FromIterator<UserInfo>(this.Login(...));
      
      





オプションで、次を指定できます。





おわりに


長所:






短所:




マイナスのほとんどは、何らかの方法で克服することができます。



テキストのエラーはPMに送信できます。

ソースコード



All Articles