IEnumerable<T> インターフェイスは、一度に 1 つの項目の値のシーケンスを返すことができるクラスによって実装されます。 一度に 1 つの項目のデータを返す利点は、処理するためにメモリにデータの完全なセットを読み込む必要がないということです。 データから 1 つの項目を読み込むのに十分なメモリを使用するだけで済みます。
IEnumerable(T) インターフェイスを実装するクラスは、For Each ループまたは LINQ クエリで使用できます。
たとえば、大きなテキスト ファイルを読み取り、特定の検索条件に一致するファイルから各行を返す必要があるアプリケーションがあるとします。 アプリケーションは LINQ クエリを使用して、指定された条件に一致する行をファイルから返します。 LINQ クエリを使用してファイルの内容に対してクエリを実行するために、アプリケーションはファイルの内容を配列またはコレクションに読み込むことができます。 ただし、配列またはコレクションにファイル全体を読み込むと、必要以上に多くのメモリが消費されます。 LINQ クエリでは、代わりに列挙可能なクラスを使用してファイルの内容を照会し、検索条件に一致する値のみを返すことができます。 一致する値が少数しか返されていないクエリでは、消費されるメモリがはるかに少なくなります。
IEnumerable<T> インターフェイスを実装するクラスを作成して、ソース データを列挙可能なデータとして公開できます。
IEnumerable(T) インターフェイスを実装するクラスには、ソース データを反復処理するためにIEnumerator<T> インターフェイスを実装する別のクラスが必要です。 これら 2 つのクラスを使用すると、データの項目を特定の型として順番に返します。
このチュートリアルでは、 IEnumerable(Of String) インターフェイスを実装するクラスと、テキスト ファイルを一度に 1 行ずつ読み取る IEnumerator(Of String) インターフェイスを実装するクラスを作成します。
注
次の手順では、一部の Visual Studio ユーザー インターフェイス要素の名前や場所がコンピューターに異なる場合があります。 これらの要素は、使用している Visual Studio エディションと使用する設定によって決まります。 詳細については、「IDEのカスタマイズ」を参照してください。
列挙可能なクラスの作成
列挙可能なクラス プロジェクトを作成する
Visual Basic の [ ファイル ] メニューの [ 新規作成 ] をポイントし、[ プロジェクト] をクリックします。
[ 新しいプロジェクト ] ダイアログ ボックスの [ プロジェクトの種類 ] ウィンドウで、 Windows が選択されていることを確認します。 [テンプレート] ウィンドウで [クラス ライブラリ] を選択します。 [ 名前 ] ボックスに「
StreamReaderEnumerable」と入力し、[OK] をクリック します。 新しいプロジェクトが表示されます。ソリューション エクスプローラーで、Class1.vb ファイルを右クリックし、[名前の変更] をクリックします。 ファイルの名前を
StreamReaderEnumerable.vbに変更し、Enter キーを押します。 ファイルの名前を変更すると、クラスの名前もStreamReaderEnumerableに変更されます。 このクラスは、IEnumerable(Of String)インターフェイスを実装します。StreamReaderEnumerable プロジェクトを右クリックし、[ 追加] をポイントして、[ 新しい項目] をクリックします。 クラス テンプレートを選択します。 [ 名前 ] ボックスに「
StreamReaderEnumerator.vb」と入力し、[OK] をクリック します。
このプロジェクトの最初のクラスは列挙可能なクラスであり、 IEnumerable(Of String) インターフェイスを実装します。 このジェネリック インターフェイスは、 IEnumerable インターフェイスを実装し、このクラスのコンシューマーが Stringとして型指定された値にアクセスできることを保証します。
IEnumerable を実装するコードを追加する
StreamReaderEnumerable.vb ファイルを開きます。
Public Class StreamReaderEnumerable後の行で、次のように入力し、Enter キーを押します。Implements IEnumerable(Of String)Visual Basic では、
IEnumerable(Of String)インターフェイスに必要なメンバーがクラスに自動的に設定されます。この列挙可能なクラスは、テキスト ファイルから一度に 1 行ずつ行を読み取ります。 次のコードをクラスに追加して、ファイル パスを入力パラメーターとして受け取るパブリック コンストラクターを公開します。
Private _filePath As String Public Sub New(ByVal filePath As String) _filePath = filePath End SubIEnumerable(Of String)インターフェイスのGetEnumerator メソッドを実装すると、StreamReaderEnumeratorクラスの新しいインスタンスが返されます。IEnumerableインターフェイスのGetEnumeratorメソッドの実装は、IEnumerable(Of String)インターフェイスのメンバーのみを公開する必要があるため、Privateできます。GetEnumeratorメソッドに対して Visual Basic によって生成されたコードを次のコードに置き換えます。Public Function GetEnumerator() As IEnumerator(Of String) _ Implements IEnumerable(Of String).GetEnumerator Return New StreamReaderEnumerator(_filePath) End Function Private Function GetEnumerator1() As IEnumerator _ Implements IEnumerable.GetEnumerator Return Me.GetEnumerator() End Function
IEnumerator を実装するコードを追加する
StreamReaderEnumerator.vb ファイルを開きます。
Public Class StreamReaderEnumerator後の行で、次のように入力し、Enter キーを押します。Implements IEnumerator(Of String)Visual Basic では、
IEnumerator(Of String)インターフェイスに必要なメンバーがクラスに自動的に設定されます。列挙子クラスは、テキスト ファイルを開き、ファイル I/O を実行してファイルから行を読み取ります。 次のコードをクラスに追加して、ファイル パスを入力パラメーターとして受け取り、読み取り用にテキスト ファイルを開くパブリック コンストラクターを公開します。
Private _sr As IO.StreamReader Public Sub New(ByVal filePath As String) _sr = New IO.StreamReader(filePath) End SubIEnumerator(Of String)インターフェイスとIEnumeratorインターフェイスの両方のCurrentプロパティは、テキスト ファイルから現在の項目をStringとして返します。IEnumerator(Of String)インターフェイスのメンバーのみを公開する必要があるため、IEnumeratorインターフェイスのCurrentプロパティの実装をPrivateできます。Currentプロパティに対して Visual Basic によって生成されたコードを次のコードに置き換えます。Private _current As String Public ReadOnly Property Current() As String _ Implements IEnumerator(Of String).Current Get If _sr Is Nothing OrElse _current Is Nothing Then Throw New InvalidOperationException() End If Return _current End Get End Property Private ReadOnly Property Current1() As Object _ Implements IEnumerator.Current Get Return Me.Current End Get End PropertyIEnumeratorインターフェイスのMoveNextメソッドは、テキスト ファイル内の次の項目に移動し、Currentプロパティによって返される値を更新します。 読み取る項目がそれ以上ない場合、MoveNextメソッドはFalseを返します。それ以外の場合、MoveNextメソッドはTrueを返します。MoveNextメソッドに次のコードを追加します。Public Function MoveNext() As Boolean _ Implements System.Collections.IEnumerator.MoveNext _current = _sr.ReadLine() If _current Is Nothing Then Return False Return True End FunctionIEnumeratorインターフェイスのResetメソッドは、テキスト ファイルの先頭を指す反復子を指示し、現在の項目の値をクリアします。Resetメソッドに次のコードを追加します。Public Sub Reset() _ Implements System.Collections.IEnumerator.Reset _sr.DiscardBufferedData() _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin) _current = Nothing End SubIEnumeratorインターフェイスのDisposeメソッドは、反復子が破棄される前にすべてのアンマネージ リソースが解放されることを保証します。StreamReaderオブジェクトによって使用されるファイル ハンドルはアンマネージ リソースであり、反復子インスタンスが破棄される前に閉じる必要があります。Disposeメソッドに対して Visual Basic によって生成されたコードを次のコードに置き換えます。Private disposedValue As Boolean = False Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' Dispose of managed resources. End If _current = Nothing _sr.Close() _sr.Dispose() End If Me.disposedValue = True End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Protected Overrides Sub Finalize() Dispose(False) End Sub
サンプル反復子の使用
コード内で列挙可能なクラスを、For Next ループや LINQ クエリなど、IEnumerableを実装するオブジェクトを必要とするコントロール構造体と共に使用できます。 次の例は、LINQ クエリの StreamReaderEnumerable を示しています。
Dim adminRequests =
From line In New StreamReaderEnumerable("..\..\log.txt")
Where line.Contains("admin.aspx 401")
Dim results = adminRequests.ToList()
こちらも参照ください
- Visual Basic での LINQ の概要
- 制御フロー
- ループ構造
- For Each...次のステートメント
.NET