IEnumerable<T>.GetEnumerator Método

Definición

Devuelve un enumerador que procesa una iteración en la colección.

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)

Devoluciones

Enumerador que se puede utilizar para recorrer en iteración la colección.

Ejemplos

En el ejemplo siguiente se muestra cómo implementar la IEnumerable<T> interfaz y usar esa implementación para crear una consulta LINQ. Al implementar IEnumerable<T>, también debe implementar IEnumerator<T> o, solo para C#, puede usar la palabra clave yield . La implementación IEnumerator<T> también requiere IDisposable que se implemente, que verá en este ejemplo.

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

public class App
{
    // Exercise 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

Comentarios

El devuelto IEnumerator<T> proporciona la capacidad de recorrer en iteración la colección mediante la exposición de una Current propiedad . Puede usar enumeradores para leer los datos de una colección, pero no para modificar la colección.

En principio, el enumerador se coloca antes del primer elemento de la colección. En esta posición, el valor de propiedad Current está sin definir. Por lo tanto, debe llamar al MoveNext método para avanzar el enumerador al primer elemento de la colección antes de leer el valor de Current.

Current devuelve el mismo objeto hasta MoveNext que se llama de nuevo como MoveNext establece Current en el elemento siguiente.

Si MoveNext pasa el final de la colección, el enumerador se coloca después del último elemento de la colección y MoveNext devuelve false. Cuando el enumerador está en esta posición, las llamadas posteriores a MoveNext también devuelven false. Si la última llamada a MoveNext se falsedevuelve , Current no está definida. No puede volver a establecer la propiedad Current en el primer elemento de la colección, sino que debe crear una nueva instancia del enumerador.

Si se realizan cambios en la colección, como agregar, modificar o eliminar elementos, el comportamiento del enumerador no está definido.

Un enumerador no tiene acceso exclusivo a la colección, por lo que un enumerador permanece válido siempre que la colección permanezca sin cambios. Si se realizan cambios en la colección, como agregar, modificar o eliminar elementos, el enumerador se invalida y puede obtener resultados inesperados. Además, la enumeración de una colección no es un procedimiento seguro para subprocesos. Para garantizar la seguridad de subprocesos, debe bloquear la colección durante el enumerador o implementar la sincronización en la colección.

Las implementaciones predeterminadas de colecciones en el System.Collections.Generic espacio de nombres no se sincronizan.

Se aplica a

Consulte también