この記事はなに?
C# Advent Calendar 2023、15日目の記事です!
14日目はtkhshiqさんです。
qiita.com
Unityの方角から来ました、エンジニアのかこです!
この記事ではIEnumeratorについて簡単に触れます。Unityのコルーチン周りについては取り扱いません。
対象
- IEnumeratorってなに?という方
- IEnumeratorって検索してもんにょりした方
- IEnumeratorって非同期処理、コルーチンでしょ?って方
「IEnumerator って?」
以下を読んでも良いし読むべきだし読めば良いんですが、今回の記事は、IEnumeratorを説明するときにUnityで非同期処理に使うとかUnityのコルーチンを使用するために用いるとだけ言及することは正直あんまりしっくりこないなという気持ちで文字を進めていきます。それはさておき、知らなくても機能する仕組みは素晴らしいですね。
learn.microsoft.com
コレクションの要素に順番にアクセスできるインターフェース
そもそも、Enumeratorという単語は「数を数える人」とか、自然言語としては「調査員」という意味になっていきます。enumerateで「列挙する」です。
余談ですが、Weblioでは「enumerator」は学習レベル25(最大30)にランク付けされています。
ejje.weblio.jp
プログラミングでは文脈によって「列挙子」だったり.NETフレームワークの文脈では「コレクションの要素を順に取り出すイテレータ」だったりしますね。今回は後者です。
その性質をもたせられるインターフェース、IEnumeratorということです。
今回の主題ではないですが、ListがIEnumerableを継承しており、意識せずともforeachなどで使われています。
IEnumeratorができること
彼には、MoveNext(), Current, Reset()というのが生えています。今回はReset以外に触れます。
例を考えるため、IEnumerableという、反復処理をサポートするインターフェースを用意してみます。
|
1 |
IEnumerable<<span class="synType">string</span>> elements <span class="synStatement">=</span> <span class="synStatement">new</span> List<<span class="synType">string</span>> { <span class="synConstant">"序"</span>, <span class="synConstant">"破"</span>, <span class="synConstant">"Q"</span> }; |
これはGetEnumeratorというメソッドを持っており、これによってIEnumeratorをもったオブジェクトを返します。
以下を見てみましょう。
|
1 2 3 4 5 6 |
IEnumerable<<span class="synType">string</span>> elements <span class="synStatement">=</span> <span class="synStatement">new</span> List<<span class="synType">string</span>> { <span class="synConstant">"序"</span>, <span class="synConstant">"破"</span>, <span class="synConstant">"Q"</span> }; IEnumerator<<span class="synType">string</span>> enumerator <span class="synStatement">=</span> elements.GetEnumerator(); <span class="synStatement">while</span> (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } |
出力は以下です
|
1 2 3 |
序 破 Q |
つまり、IEnumeratorなenumeratorくんは、MoveNext()によって、参照している要素を次に移動させています。
なお、enumeratorは生成時、最初の要素の更に前、無(?)に位置しており、whileに入った最初の実行で、最初の要素、序に移動しています。
結果として、enumerator.Currentで1つ1つ出力され、最終的に、MoveNext()がfalseを返しループから抜けます。
foreachに突っ込んで、見る
さて、要素を表示するだけなら当然、以下でもいいはずです。
|
1 2 3 4 5 |
List<<span class="synType">string</span>> evaList <span class="synStatement">=</span> <span class="synStatement">new</span> List<<span class="synType">string</span>> { <span class="synConstant">"序"</span>, <span class="synConstant">"破"</span>, <span class="synConstant">"Q"</span> }; <span class="synStatement">foreach</span> (<span class="synType">var</span> eva <span class="synStatement">in</span> evaList) { Console.WriteLine(eva); } |
では、これをIDE(Rider)でLow-Level C# にしてみます。(以下のコードは表記統一のために{}と改行を追加していますので、完全にそのままではありません)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
List<<span class="synType">string</span>>.Enumerator enumerator <span class="synStatement">=</span> evaList.GetEnumerator(); <span class="synStatement">try</span> { <span class="synStatement">while</span> (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } } <span class="synStatement">finally</span> { enumerator.Dispose(); } |
この通り、Enumeratorにしておおよそ同じことをしていました。
ListはIEnumerableを継承しているのでGetEnumeratorを呼び出せています。
こんな感じで、普段気にせずforeachを使用している際にもIEnumerator(Enumerator)の助けがあるとわかりました。IEnumerator、お前だったのか。
シンプルな役割
思いの外(?)身近にいたIEnumerator。まだよそよそしいですが、少し仲良くなれた気がします。
もしUnityにおけるコルーチンの仕組みが知りたい場合、調べてみることをおすすめします。基本はMoveNextです。
