C# - イテレーター(iterator)
イテレーター(iterator)
イテレーターとは
反復子とも呼ばれ、集合の個々の要素に対して繰り返し処理を行うためのもの
です。
iterate の直訳が ”繰り返す" なので、繰り返すためのものという意味で名付けられています。
イテレーターを使うと、関数やプロパティの get アクセサーにも foreach 文を使って繰り返し処理ができるようになります。
foreach 文の実態
foreach 文は繰り返し処理をする際に使われる関数です。
(例)
//list内の要素を取り出して繰り返し処理 var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 }; foreach (int element in fibNumbers) { Debug.Log(element); }
通常であれば、list と配列は別物なので、list を引数にもつ関数には配列は使えません。しかし、foreach 文の実態は、IEnumerable インターフェースを介した要素へのアクセスです。そのため、IEnumerable インターフェースを実装しているならどんなコレクションクラスの要素でも読み出すことが出来ます。
foreach 文であれば、listでも配列でも辞書でも繰り返し処理ができるということです。
インターフェースについての説明は、以前まとめましたので、そちらの記事をご覧ください。
イテレーター構文の書き方(C#2.0~)
foreach 文は IEnumerable インターフェースを介した要素へのアクセスでした。foreach 文を実装するには、IEnumerable インターフェースを実装する必要があります。
C#2.0 以降では、イテレーター構文を使うことで、IEnumerable インターフェースの実装するクラスを自動生成してくれるので、foreach 文で利用可能なコレクションを返すメソッドやプロパティを簡単に実装することができます。
イテレーター(イテレーターブロック)の書き方は次の通りです。
(イテレーターの書き方)
- 戻り値の型が次のいずれか
- System.Collections.IEnumerator
- System.Collections.Generic.IEnumerator
- System.Collections.IEnumerable
- System.Collections.Generic.IEnumerable
- 値を返す場合は return ではなく yield return を使う
- 処理を終了する場合は break ではなく yield break を使う
(例)
using System.Collections.Generic; using UnityEngine; public class iteratorSample : MonoBehaviour { // Start is called before the first frame update void Start() { IteratorTest iTest = new IteratorTest(); foreach (var i in iTest.IteratorMethod()) { Debug.Log(i); } foreach (var i in iTest.IteratorProperty) { Debug.Log(i); } } } class IteratorTest { //イテレーター, 関数 public IEnumerable<int> IteratorMethod() { for (var i = 0; i < 10; i++) { // yield returnに指定するのは <T> で指定した型の値 yield return i; } } //イテレーター, プロパティ public IEnumerable<string> IteratorProperty { get { for (var i = 10; i < 20; i++) { // yield returnに指定するのは <T> で指定した型の値 yield return i.ToString(); } } } }
上の例では、for 文を使いましたが、while 文を使ったり、yield return を並べてもよいです。
public IEnumerable<int> IteratorMethod() { yield return 1; yield return 2; yield return 3; }
変数の型
using System.Collections; using System.Collections.Generic; using UnityEngine; public class iteratorSample : MonoBehaviour { void Start() { IteratorTest iTest = new IteratorTest(); foreach (var i in iTest.IteratorMethod(2, 8)) //引数が追加された { Debug.Log(i); } } } class IteratorTest { //イテレーター, 関数 //戻り値の型は指定していない public IEnumerable IteratorMethod(int From, int To) //引数を指定 { for (var i = From; i < To; i++) { yield return i; } yield return "aaa"; yield return 2.73f; } }