解析はenumeratorモードを使って非同期操作を簡略化する詳細解を使う。
まず同期コードを見ます。public int SumPageSizes(IList<Uri>uris){ int total=0 foreach(var uri in uris){ status Text.Text=string.Format(「Found{0}bytes...」、total); var data=new WebCient().DownloadData(uri); total+=data.Length; } status Text.Text=string.Format(「Found{0}bytes total」、total); return total;このコードは比較的簡単で、一つずつの同期方式でUri Dataを取得し、統計を行います。非同期方式で統計を一つずつ使うなら、どう計算すればいいですか?以前、醜いコードをデモンストレーションしましたが、大体次の通りです。 WebCient webClient=new WebClient() webClient.DownloadData Completted+=(s,e)=> { // A対象を使って、何かをする。 WebClient webClient 2=new WebClient() webClient 2.DownloadData Completted+=(s 2,e 2)=> { //Bの相手を使って、何かをします。 // 再帰的にDownloadDataAyncに行きます。 }; webClient 2.DownloadDataAync(new Uri(「Bの住所」); }; webClient.DownloadDataAync(new Uri);もちろん、住所が二つしかないと確定したら、この方法はいいかもしれません。複数の住所があれば再帰的に呼び出さなければなりません。Enumeratorを使って非同期操作を簡略化するにはどうすればいいですか?public void SumPageSizesAsync(IList<Uri>uris){ SumPageSizes AsyncHelper(uris.Get Enumerator(),0);prvate void SumPageSizes AsyncHelper(IEnumerator<Uri>enumerator、int total){ if(enumerator.MoveNext(){ status Text.Text=string.Format(「Found{0}bytes...」、total); var client=new WebCient() client.DownloadData Completted+=((sender,e)=>{ SumPageSizes AsyncHelper; }; client.DownloadDataAync; } else{ status Text.Text=string.Format(「Found{0}bytes total」、total); enumerator.Discpose() } } SumPageSizes AsyncHelperにより、非同期的にA->非同期的にB->非同期的にCを呼び出すことができます。まず、理由を説明します。urisはA,B,C.SumPageSizes AsyncHelperがあると仮定します。
方法はまずAを呼び出します。Aの後ろにBがありますので、enumerator.MoveNext()はTrueに戻ります。そしてDownloadData Complettedのイベントが終わったら、Bを呼び出します。同様にBの後ろにCがありますので、enumerator.MoveNext()は引き続きTrueに戻ります。Cの呼び出しが完了しました。Cの後ろにはないので、enumerator.MoveNext()はFalseに戻ります。全部ダウンロード済みと考えられます。だから最終結果を返します。
asyncとawaitを使って実現すれば、コードは以下の通りです。public async Task<int>SumPageSizes Aync 2(IList<Uri>uris){ int total=0 Char charText='A' foreach(var uri in uris) { var data=await new WebClient().Down loadData Tasky(uri); total+=data.Length; Consolie.WriteLine("Thread Id:{0]:呼び出し{1}のアドレスFound{2}bytes…{3} Thread.Current Thread.ManagedThreadId,charText,total,DateTime.Now); charText=Covert.ToChar(charText+1) } Consolie.WriteLine(「Thread Id:{0]:全部完了しました。Found{1}bytes total{2} Thread.Current Thread.ManagedThreadId,total,DateTime.Now); return total;
方法はまずAを呼び出します。Aの後ろにBがありますので、enumerator.MoveNext()はTrueに戻ります。そしてDownloadData Complettedのイベントが終わったら、Bを呼び出します。同様にBの後ろにCがありますので、enumerator.MoveNext()は引き続きTrueに戻ります。Cの呼び出しが完了しました。Cの後ろにはないので、enumerator.MoveNext()はFalseに戻ります。全部ダウンロード済みと考えられます。だから最終結果を返します。
asyncとawaitを使って実現すれば、コードは以下の通りです。public async Task<int>SumPageSizes Aync 2(IList<Uri>uris){ int total=0 Char charText='A' foreach(var uri in uris) { var data=await new WebClient().Down loadData Tasky(uri); total+=data.Length; Consolie.WriteLine("Thread Id:{0]:呼び出し{1}のアドレスFound{2}bytes…{3} Thread.Current Thread.ManagedThreadId,charText,total,DateTime.Now); charText=Covert.ToChar(charText+1) } Consolie.WriteLine(「Thread Id:{0]:全部完了しました。Found{1}bytes total{2} Thread.Current Thread.ManagedThreadId,total,DateTime.Now); return total;