半人前プログラマーの技術談議

開発した物と,C#を入門者向けに解説した記事を書いています!

【C# コレクション】イテレータ① part3-5

calendar

reload

こんにちは!シロウです!

今回はイテレータについて紹介します!

今回の内容は結構重要ではあるんですが,難しいので番外partでもよかったかもしれません.

イテレータ(反復子)

概要

イテレータ(iterator)は,配列やリストなどのデータ構造の各要素に対しての繰り返し処理に使われるもののことです.

結構抽象的に説明しましたが,Wikipediaでは,

イテレータ英語iterator)とは、プログラミング言語において配列やそれに類似する集合的データ構造(コレクションあるいはコンテナ)の各要素に対する繰り返し処理の抽象化である。実際のプログラミング言語では、オブジェクトまたは文法などとして現れる。JISでは反復子(はんぷくし)と翻訳されている

というように説明されています.

簡単に言えば,繰り返し処理をする為の情報です.

ちなみに,for文でよく使われている,int i = 0;の i はイテレータの頭文字を取ったものです.

foreach文によって,コレクションクラス(配列やリスト)に対して列挙処理ができるのは,イテレータを実装している事が前提になっています.

今更ですが,foreach文の処理を見ていきます.

コレクションの全ての要素を1回ずつ呼び出し,処理をします.

これを一般に列挙と呼んでいるわけです.

foreach文の中身の処理を知る為には,イテレータについて知る必要があります.

イテレータを扱う上で,2つのインターフェースについて知っておく必要があります.

 

IEnumerable

1つ目のインターフェースが,IEnumerableインターフェースです.

IEnumerableインターフェースは,コレクションに対する単純な反復処理をサポートする列挙子を公開するインターフェースです.

簡単に言えば,繰り返し処理をする為の機能を与えるものです.

IEnumerableインターフェースは,

IEnumerator GetEnumerator()メソッド

の実装を強制します.

※厳密には,属性が付いています.

 

インターフェースが戻り値の場合は,インターフェースを実装したクラスのインスタンスが戻り値になります.

では,次はIEnumeratorインターフェースについて見てみましょう.

 

IEnumerator

2つ目のインターフェースが,IEnumeratorインターフェースです.

IEnumeratorインターフェースは,コレクションに対する単純な反復処理をサポートするインターフェースです.

IEnumeratorインターフェースは,列挙子とも呼ばれています.

IEnumeratorインターフェースは,

Object Currentプロパティ(現在の要素を取得するプロパティ),

bool MoveNext()メソッド(次の要素へ移動するメソッド,移動できればture,できなければfalseを返す),

void Reset()メソッド(コレクションの一番最初の要素へ戻すメソッド)

の実装を強制します.

IEnumerableインターフェースは列挙子を丸ごと返すのに対し,IEnumeratorインターフェースは列挙子の情報をプロパティとメソッドから定義し直す事が出来るとも言えそうです.

foreach文では,これらの情報を元に列挙しているわけです.

なので,foreach文を使うには,IEnumerable(IEnumerator)インターフェースの実装が必須となります.

 

イテレータ構文

今回一番やりたい内容がこれです.

自作コレクションクラスを作ってイテレータについて話すと長くなってしまうので,

IEnumerable(IEnumerator)インターフェースをメソッドの戻り値にした場合を考えていきます.

IEnumarableインターフェースを戻り値にするという事は,列挙子の情報を持っているクラスのインスタンスが戻り値になるという事になります.

しかし,IEnumerableインターフェースは,IEnumeratorインターフェースを返すとか考えながらプログラムを書くのは非常に面倒です.

もっとシンプルに書く為に,イテレータ構文というものがあります.

イテレータ構文は,return の代わりに,yield return にすることで,列挙される(列挙子を持つ)値を返す事ができます.

つまり,yield return は IEnumerable(IEnumerator) を返す事ができます.

 

 

実行結果

 

Testメソッドが,foreachによって列挙できるのは,Testメソッドの戻り値がIEnumarable(IEnumarator)だからです.

ここで,Testメソッドが呼び出されている所に着目すると,yield returnによって値を返す時に,Testメソッドは一度それ以降の処理を中断して,Mainメソッドの処理に戻ります.その後,Testメソッドが再度呼び出されると,処理を中断した箇所から次のyield returnまで処理を再開します.

非同期処理に似ていますが,違いはシングルスレッドで実現できるっていう所ですね.

 

まとめ

foreach文を使うには,IEnumerable(IEnumarator)インターフェースの実装が必須.

yield returnで簡単にできる.

 

 

今回はここまで

実は,今回の内容に関して筆者はあまり理解していません.

この記事は分かり次第色々更新していく予定です…

自作コレクションクラスの話になるともっと複雑になるんだろうなぁ…

コレクション編は一旦ここで区切ろうかと思っています.

そろそろジェネリックとか関数指向を書きたいので.