Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9360

再入門C#:yield

$
0
0

非同期処理が出てくる中で、yieldが出てきて、はて、C#でどうだっけ?と思ったので書いてみます。yieldは JavaScriptとかで出てきました。ちなみに、アメリカに住んでいると、信号機のところにYeildって書いてあって、その意味は状況を見て曲がっていいよです。

C# の yield

C#のYield は、IEnumerable<T>や、IEnumerator<T>が戻り値になるようなメソッドで使用可能です。簡単な例を示すとこんな感じです。

こういうメソッドを書いておいて、

staticIEnumerable<int>Generate(){for(inti=0;i<10;i++){yieldreturni;Thread.Sleep(TimeSpan.FromSeconds(1));}}

こんな風に使います

staticvoidDisplay(){foreach(intiinGenerate()){Console.WriteLine($"Number: {i}");}}

すると、1秒ごとに

Number: 0
Number: 1
  :

といった感じで表示されていきます。IEnumerable<T>は、シンプルなイテレーターを表すインターフェイスで、実装クラスはGetEnumerator()を実装する必要があります。IEnumerator は、Dispose(), MoveNext(), Reset() の三つのメソッドをもっていて、yield のところで待ち受けをしているのですが、MoveNext() が呼ばれたタイミングで、yieldのところで値が返ります。

この仕組みはLinqでも使われているものです。

これと似たメソッドは下記のように書けますが、1秒ごとに待たせるというのは難しくて、メソッドが呼ばれた時点で、表示がかかる前に、このメソッドが10秒時間がかかってから、一気にすべての行が表示されます。

staticIEnumerable<int>GenerateWithCollection(){varnumbers=newList<int>();for(inti=0;i<10;i++){numbers.Add(i);Thread.Sleep(TimeSpan.FromSeconds(1));}returnnumbers;}

Map を実装する

これを使って何か実装してみましょう。昔私はScalaを書いていて、MapやFlatMapが懐かしいなと思っていました。C#だと、Linqで書けるのですが、あえてMapを自分で実装してみましょう。うお、めっちゃ簡単や!

publicstaticclassExtensions{publicstaticIEnumerable<U>Map<T,U>(thisIEnumerable<T>self,Func<T,U>func){foreach(variteminself){varconverted=func(item);yieldreturnconverted;}}}

じゃあ使ってみよう。ちなみに、これを実行すると何も起こりませんw。なぜなら、yieldで書いたものは遅延評価になるからです。Linqが遅延評価なのも同じインターフェイスを使っているからです。

privatestaticvoidTestOriginalMap(){varnames=newList<string>{"ushio","yamada","kim"};varnamesWithRespect=names.Map(item=>{varwithRespect=$"{item} sama";Console.WriteLine(withRespect);returnwithRespect;});}

じゃあ、しっかり要素にアクセスしてみましょう。

privatestaticvoidTestOriginalMap(){varnames=newList<string>{"ushio","yamada","kim"};varnamesWithRespect=names.Map(item=>{varwithRespect=$"{item} sama";Console.WriteLine(withRespect);returnwithRespect;});foreach(varnameinnamesWithRespect){Console.WriteLine($"{name} sama de gozaimasu ne.");}}

実行結果

ushio sama
ushio sama sama de gozaimasu ne.
yamada sama
yamada sama sama de gozaimasu ne.
kim sama
kim sama sama de gozaimasu ne.

非同期型のIEnumerable

非同期型のものもあります。IAsyncEnumerable<T>を返す型を定義すると、asyncメソッドの中でyieldを使うことができます。その際、イテレータは、foreachにawaitキーワードをつけてループを回すことができます。

staticasyncIAsyncEnumerable<int>GenerateAsync(){for(inti=0;i<10;i++){yieldreturni;awaitTask.Delay(TimeSpan.FromSeconds(1));}}staticasyncTaskDisplayAsync(){awaitforeach(variinGenerateAsync()){Console.WriteLine($"NumberAsync: {i}");}}

参考


Viewing all articles
Browse latest Browse all 9360

Latest Images

Trending Articles