チュートリアル: Visual Basic での IEnumerable(Of T) の実装
IEnumerable<T> インターフェイスは、値のシーケンスを、一度に 1 項目ずつ返すことができるクラスによって実装されます。 一度に 1 項目ずつデータを返す利点は、データ セット全体をメモリに読み込んで操作する必要がないことです。 データから 1 つの項目を読み込むのに必要なメモリを使用するだけで済みます。 IEnumerable(T)
インターフェイスを実装するクラスを、For Each
ループまたは LINQ クエリで使用できます。
たとえば、大きなテキスト ファイルを読み取り、そのファイルから、特定の検索条件に一致する各行を返す必要があるアプリケーションがあるとします。 アプリケーションは LINQ クエリを使用して、指定された条件に一致する行をファイルから返します。 LINQ クエリを使用してファイルのコンテンツにクエリを実行するために、アプリケーションでは、ファイルのコンテンツを配列またはコレクションに読み込むことができます。 ただし、ファイル全体を配列またはコレクションに読み込むと、必要以上にメモリが消費されます。 LINQ クエリは、列挙可能なクラスを使用してファイルのコンテンツにクエリを実行し、検索条件に一致する値のみを返すことができます。 一致する値だけをいくつか返すクエリの場合、消費メモリは格段に少なくなります。
IEnumerable<T> インターフェイスを実装するクラスを作成して、ソース データを、列挙可能なデータとして公開できます。 IEnumerable(T)
インターフェイスを実装するクラスには、ソース データを反復処理するために IEnumerator<T> インターフェイスを実装する別のクラスが必要です。 この 2 つのクラスを使用すると、データの項目を特定の型として順番に返すことができます。
このチュートリアルでは、IEnumerable(Of String)
インターフェイスを実装するクラスと IEnumerator(Of String)
インターフェイスを実装するクラスを作成して、テキスト ファイルを 1 行ずつ読み取ります。
注意
次の手順で参照している 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)
IEnumerable(Of String)
インターフェイスに必要なメンバーが、クラスに自動入力されます。この列挙可能なクラスは、テキスト ファイルから 1 行ずつ行を読み取ります。 次のコードをクラスに追加して、ファイル パスを入力パラメーターとして取るパブリック コンストラクターを公開します。
Private _filePath As String Public Sub New(ByVal filePath As String) _filePath = filePath End Sub
IEnumerable(Of String)
インターフェイスの GetEnumerator メソッドの実装は、StreamReaderEnumerator
クラスの新しいインスタンスを返します。IEnumerable(Of String)
インターフェイスのメンバーのみを公開する必要があるため、IEnumerable
インターフェイスのGetEnumerator
メソッドの実装はPrivate
にできます。GetEnumerator
メソッド用に生成されたコードを次のコードに置き換えます。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)
IEnumerator(Of String)
インターフェイスに必要なメンバーが、クラスに自動入力されます。列挙子クラスはテキスト ファイルを開き、ファイルから行を読み取るためにファイル I/O を実行します。 次のコードをクラスに追加して、ファイル パスを入力パラメーターとして取るパブリック コンストラクターを公開し、読み取るテキスト ファイルを開きます。
Private _sr As IO.StreamReader Public Sub New(ByVal filePath As String) _sr = New IO.StreamReader(filePath) End Sub
IEnumerator(Of String)
インターフェイスとIEnumerator
インターフェイスの両方のCurrent
プロパティが、テキスト ファイルから現在の項目をString
として返します。IEnumerator(Of String)
インターフェイスのメンバーのみを公開する必要があるため、IEnumerator
インターフェイスのCurrent
プロパティの実装はPrivate
にできます。Current
プロパティ用に生成されたコードを次のコードに置き換えます。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 Property
IEnumerator
インターフェイスの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 Function
IEnumerator
インターフェイスのReset
メソッドは、テキスト ファイルの先頭を指すよう反復子に指示し、現在の項目の値をクリアします。Reset
メソッドに次のコードを追加します。Public Sub Reset() _ Implements System.Collections.IEnumerator.Reset _sr.DiscardBufferedData() _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin) _current = Nothing End Sub
IEnumerator
インターフェイスのDispose
メソッドは、反復子が破棄される前にすべてのアンマネージ リソースが解放されることを保証します。StreamReader
オブジェクトによって使用されるファイル ハンドルはアンマネージ リソースです。このハンドルは、反復子インスタンスが破棄される前に閉じる必要があります。Dispose
メソッド用に生成されたコードを次のコードに置き換えます。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()
関連項目
.NET