質問の背景
イテレータは、コレクションを反復処理する必要が出てきたことで、プログラミング言語の重要な部分となりました。Visual Basicでは、.NETバージョンからIEnumerable/IEnumeratorのサポートが追加され、独自の列挙可能コレクションを実装したり、For Eachループを使用してコレクションの内容に便利で簡潔にアクセスすることが可能となりました。
問題
多くの開発者は、組み込みコレクションのみを使用するか、IEnumerableインターフェイスを正しく実装しないため、For Eachによるオブジェクトの反復が不可能になる場合があります。また、CurrentやMoveNextを介したイテレータの状態管理が複雑になります。
解決策
反復処理をサポートするために、型はIEnumerable(またはジェネリックIEnumerable(Of T))インターフェイスを実装します。IEnumeratorを実装したオブジェクトを返すGetEnumerator関数を実装してください。VB.NETではVB 2015以降、Yieldキーワードを用いたイテレーターメソッドも利用できます。これにより、反復処理の実装が大幅に簡素化されます。
コードの例:
Imports System.Collections Public Class SimpleCollection Implements IEnumerable Private arr() As Integer = {1, 2, 3} Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator For Each i In arr Yield i ' VB 2015以降 Next End Function End Class ' 使用方法: For Each n As Integer In New SimpleCollection() Console.WriteLine(n) Next
主な特徴:
For Eachをサポートするために、IEnumerableとIEnumeratorの両方のインターフェイスを実装する必要がありますか?
いいえ、IEnumerableを実装し、互換性のあるイテレータを返すだけで十分です。反復処理を実装したい場合は、内包されているコレクションの既存のIEnumeratorを使用できます。ただし、完全なカスタマイズを行うには両方の部分を実装する必要があります。
コードの例:
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return arr.GetEnumerator() ' 組み込みの配列イテレータを使用 End Function
Visual BasicでIEnumerableを明示的に(Explicit Interface Implementation)実装できますか?
はい、特にコレクションに自分自身のGetEnumeratorがあり、インターフェイスの実装を隠したい場合には、明示的にインターフェイスを実装することができます。このようなGetEnumeratorを直接呼び出すことはできませんが、For Eachは機能します。
コードの例:
Public Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator ' ...メソッドの本体 End Function
GetEnumeratorがNothingを返すとどうなりますか?
コレクションの最初の反復試行時に例外がスローされます。For Eachは正しいイテレータを期待するためです。
コレクションクラスがIEnumerableを実装しておらず、要素を反復処理するための個別のNextメソッドが作成されました。結果として、一般的なメソッドやFor Eachでは使用できなくなり、追加のメソッドを書く必要があります。
利点:
欠点:
開発者がIEnumerableとGetEnumeratorを実装し、コレクションがFor Eachで機能し、LINQと統合されました。
利点:
欠点: