IEnumerable<T>.GetEnumerator メソッド

定義

コレクションを反復処理する列挙子を返します。

public:
 System::Collections::Generic::IEnumerator<T> ^ GetEnumerator();
public System.Collections.Generic.IEnumerator<out T> GetEnumerator ();
public System.Collections.Generic.IEnumerator<T> GetEnumerator ();
abstract member GetEnumerator : unit -> System.Collections.Generic.IEnumerator<'T>
Public Function GetEnumerator () As IEnumerator(Of Out T)
Public Function GetEnumerator () As IEnumerator(Of T)

戻り値

IEnumerator<T>

コレクションの反復処理に使用できる列挙子。

次の例では、 インターフェイスを実装し、その実装を使用して IEnumerable<T> LINQ クエリを作成する方法を示します。 を実装 IEnumerable<T> する場合は、 または を実装する必要があります IEnumerator<T> 。C# の場合のみ 、yield キーワードを使用できます。 を実装 IEnumerator<T> するには IDisposable 、この例で確認できる実装も必要です。

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class App
{
    // Excercise the Iterator and show that it's more
    // performant.
    public static void Main()
    {
        TestStreamReaderEnumerable();
        Console.WriteLine("---");
        TestReadingFile();
    }

    public static void TestStreamReaderEnumerable()
    {
        // Check the memory before the iterator is used.
        long memoryBefore = GC.GetTotalMemory(true);
      IEnumerable<String> stringsFound;
        // Open a file with the StreamReaderEnumerable and check for a string.
      try {
         stringsFound =
               from line in new StreamReaderEnumerable(@"c:\temp\tempFile.txt")
               where line.Contains("string to search for")
               select line;
         Console.WriteLine("Found: " + stringsFound.Count());
      }
      catch (FileNotFoundException) {
         Console.WriteLine(@"This example requires a file named C:\temp\tempFile.txt.");
         return;
      }

        // Check the memory after the iterator and output it to the console.
        long memoryAfter = GC.GetTotalMemory(false);
        Console.WriteLine("Memory Used With Iterator = \t"
            + string.Format(((memoryAfter - memoryBefore) / 1000).ToString(), "n") + "kb");
    }

    public static void TestReadingFile()
    {
        long memoryBefore = GC.GetTotalMemory(true);
      StreamReader sr;
      try {
         sr = File.OpenText("c:\\temp\\tempFile.txt");
      }
      catch (FileNotFoundException) {
         Console.WriteLine(@"This example requires a file named C:\temp\tempFile.txt.");
         return;
      }

        // Add the file contents to a generic list of strings.
        List<string> fileContents = new List<string>();
        while (!sr.EndOfStream) {
            fileContents.Add(sr.ReadLine());
        }

        // Check for the string.
        var stringsFound =
            from line in fileContents
            where line.Contains("string to search for")
            select line;

        sr.Close();
        Console.WriteLine("Found: " + stringsFound.Count());

        // Check the memory after when the iterator is not used, and output it to the console.
        long memoryAfter = GC.GetTotalMemory(false);
        Console.WriteLine("Memory Used Without Iterator = \t" +
            string.Format(((memoryAfter - memoryBefore) / 1000).ToString(), "n") + "kb");
    }
}

// A custom class that implements IEnumerable(T). When you implement IEnumerable(T),
// you must also implement IEnumerable and IEnumerator(T).
public class StreamReaderEnumerable : IEnumerable<string>
{
    private string _filePath;
    public StreamReaderEnumerable(string filePath)
    {
        _filePath = filePath;
    }

    // Must implement GetEnumerator, which returns a new StreamReaderEnumerator.
    public IEnumerator<string> GetEnumerator()
    {
        return new StreamReaderEnumerator(_filePath);
    }

    // Must also implement IEnumerable.GetEnumerator, but implement as a private method.
    private IEnumerator GetEnumerator1()
    {
        return this.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator1();
    }
}

// When you implement IEnumerable(T), you must also implement IEnumerator(T),
// which will walk through the contents of the file one line at a time.
// Implementing IEnumerator(T) requires that you implement IEnumerator and IDisposable.
public class StreamReaderEnumerator : IEnumerator<string>
{
    private StreamReader _sr;
    public StreamReaderEnumerator(string filePath)
    {
        _sr = new StreamReader(filePath);
    }

    private string _current;
    // Implement the IEnumerator(T).Current publicly, but implement
    // IEnumerator.Current, which is also required, privately.
    public string Current
    {

        get
        {
            if (_sr == null || _current == null)
            {
                throw new InvalidOperationException();
            }

            return _current;
        }
    }

    private object Current1
    {

        get { return this.Current; }
    }

    object IEnumerator.Current
    {
        get { return Current1; }
    }

    // Implement MoveNext and Reset, which are required by IEnumerator.
    public bool MoveNext()
    {
        _current = _sr.ReadLine();
        if (_current == null)
            return false;
        return true;
    }

    public void Reset()
    {
        _sr.DiscardBufferedData();
        _sr.BaseStream.Seek(0, SeekOrigin.Begin);
        _current = null;
    }

    // Implement IDisposable, which is also implemented by IEnumerator(T).
    private bool disposedValue = false;
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposedValue)
        {
            if (disposing)
            {
                // Dispose of managed resources.
            }
            _current = null;
            if (_sr != null) {
               _sr.Close();
               _sr.Dispose();
            }
        }

        this.disposedValue = true;
    }

     ~StreamReaderEnumerator()
    {
        Dispose(disposing: false);
    }
}
// This example displays output similar to the following:
//       Found: 2
//       Memory Used With Iterator =     33kb
//       ---
//       Found: 2
//       Memory Used Without Iterator =  206kb
Imports System.IO
Imports System.Collections
Imports System.Collections.Generic
Imports System.Linq

Public Module App
   ' Excercise the Iterator and show that it's more performant.
   Public Sub Main()
      TestStreamReaderEnumerable()
      Console.WriteLine("---")
      TestReadingFile()
   End Sub

   Public Sub TestStreamReaderEnumerable()
        ' Check the memory before the iterator is used.
        Dim memoryBefore As Long = GC.GetTotalMemory(true)
      Dim stringsFound As IEnumerable(Of String)
        ' Open a file with the StreamReaderEnumerable and check for a string.
      Try
         stringsFound =
               from line in new StreamReaderEnumerable("c:\temp\tempFile.txt")
               where line.Contains("string to search for")
               select line
         Console.WriteLine("Found: {0}", stringsFound.Count())
      Catch e As FileNotFoundException
         Console.WriteLine("This example requires a file named C:\temp\tempFile.txt.")
         Return
      End Try

        ' Check the memory after the iterator and output it to the console.
        Dim memoryAfter As Long = GC.GetTotalMemory(false)
        Console.WriteLine("Memory Used with Iterator = {1}{0} kb",
                        (memoryAfter - memoryBefore)\1000, vbTab)
   End Sub

   Public Sub TestReadingFile()
        Dim memoryBefore As Long = GC.GetTotalMemory(true)
      Dim sr As StreamReader
      Try
         sr = File.OpenText("c:\temp\tempFile.txt")
      Catch e As FileNotFoundException
         Console.WriteLine("This example requires a file named C:\temp\tempFile.txt.")
         Return
      End Try

        ' Add the file contents to a generic list of strings.
        Dim fileContents As New List(Of String)()
        Do While Not sr.EndOfStream
            fileContents.Add(sr.ReadLine())
      Loop

        ' Check for the string.
        Dim stringsFound =
            from line in fileContents
            where line.Contains("string to search for")
            select line

      sr.Close()
      Console.WriteLine("Found: {0}", stringsFound.Count())

        ' Check the memory after when the iterator is not used, and output it to the console.
        Dim memoryAfter As Long = GC.GetTotalMemory(False)
        Console.WriteLine("Memory Used without Iterator = {1}{0} kb",
                        (memoryAfter - memoryBefore)\1000, vbTab)
   End Sub
End Module

' A custom class that implements IEnumerable(T). When you implement IEnumerable(T),
' you must also implement IEnumerable and IEnumerator(T).
Public Class StreamReaderEnumerable : Implements IEnumerable(Of String)
    Private _filePath As String

    Public Sub New(filePath As String)
        _filePath = filePath
    End Sub

    ' Must implement GetEnumerator, which returns a new StreamReaderEnumerator.
    Public Function GetEnumerator() As IEnumerator(Of String) _
          Implements IEnumerable(Of String).GetEnumerator
        Return New StreamReaderEnumerator(_filePath)
    End Function

    ' Must also implement IEnumerable.GetEnumerator, but implement as a private method.
    Private Function GetEnumerator1() As IEnumerator _
          Implements IEnumerable.GetEnumerator
        Return Me.GetEnumerator()
    End Function
End Class

' When you implement IEnumerable(T), you must also implement IEnumerator(T),
' which will walk through the contents of the file one line at a time.
' Implementing IEnumerator(T) requires that you implement IEnumerator and IDisposable.
Public Class StreamReaderEnumerator : Implements IEnumerator(Of String)
    Private _sr As StreamReader

    Public Sub New(filePath As String)
        _sr = New StreamReader(filePath)
    End Sub

    Private _current As String

    ' Implement the IEnumerator(T).Current Publicly, but implement
    ' IEnumerator.Current, which is also required, privately.
    Public ReadOnly Property Current As String _
          Implements IEnumerator(Of String).Current
        Get
            If _sr Is Nothing OrElse _current Is Nothing
                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

    ' Implement MoveNext and Reset, which are required by IEnumerator.
    Public Function MoveNext() As Boolean _
          Implements IEnumerator.MoveNext
        _current = _sr.ReadLine()
        if _current Is Nothing Then Return False

        Return True
    End Function

    Public Sub Reset() _
          Implements IEnumerator.Reset
        _sr.DiscardBufferedData()
        _sr.BaseStream.Seek(0, SeekOrigin.Begin)
        _current = Nothing
    End Sub

    ' Implement IDisposable, which is also implemented by IEnumerator(T).
    Private disposedValue As Boolean = False
    Public Sub Dispose() _
          Implements IDisposable.Dispose
        Dispose(disposing:=True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' Dispose of managed resources.
            End If

            _current = Nothing
            If _sr IsNot Nothing Then
               _sr.Close()
               _sr.Dispose()
            End If
        End If

        Me.disposedValue = True
    End Sub

    Protected Overrides Sub Finalize()
        Dispose(disposing:=False)
    End Sub
End Class
' This example displays output similar to the following:
'       Found: 2
'       Memory Used With Iterator =     33kb
'       ---
'       Found: 2
'       Memory Used Without Iterator =  206kb

インターフェイスを実装する方法を示す別の C# の例については、「 IEnumerable<T> ジェネリック サンプル」 を参照してください。 このサンプルでは、 を実装 yield する代わりに キーワードを使用します IEnumerator<T>

注釈

返される は IEnumerator<T> 、プロパティ を公開してコレクションを反復処理する機能を提供 Current します。列挙子を使用してコレクション内のデータを読み取り、コレクションを変更することはできません。

最初、列挙子はコレクションの先頭の要素の前に位置付けられます。 この位置では、Current が未定義です。 そのため、Current の値を読み取る前に、MoveNext メソッドを呼び出し、列挙子をコレクションの最初の要素に進める必要があります。

Current は、次の要素に設定して MoveNext 再び呼び出 MoveNext されるまで、同 Current じ オブジェクトを返します。

MoveNext がコレクションの末尾を通過した場合、列挙子がコレクション内の最後の要素の後に配置され、MoveNextfalse を返します。 列挙子がこの位置にある場合、後続の MoveNext 呼び出しも false を返します。 への最後の呼び出 MoveNext しが 返された false 場合、 Current は未定義です。 Current を、再度、コレクションの最初の要素に設定することはできません。列挙子の新しいインスタンスを作成する必要があります。

要素の追加、変更、削除など、コレクションに変更を加えた場合、列挙子の動作は未定義になります。

列挙子はコレクションへの排他的アクセス権を持たないので、コレクションが変更されない限り、列挙子は有効なままになります。 要素の追加、変更、削除など、コレクションに変更を加えた場合、列挙子は無効にされ、予期しない結果が発生する可能性があります。 また、コレクションの列挙はスレッド セーフなプロシージャではありません。 スレッドセーフを保証するには、列挙子の間にコレクションをロックするか、コレクションの同期を実装する必要があります。

名前空間内のコレクションの既定の System.Collections.Generic 実装は同期されません。

適用対象

こちらもご覧ください