2011-09-05 23 views
48

Tengo problemas para recordar cómo (pero no por qué) utilizar IEnumerator s en C#. Estoy acostumbrado a Java con su maravillosa documentación que explica todo a los principiantes bastante bien. Entonces, por favor, tengan paciencia conmigo.Uso simple de IEnumerator (por ejemplo)

He intentado aprender de otras respuestas en estas tablas en vano. En lugar de hacer una pregunta genérica que ya se haya formulado antes, tengo un ejemplo específico que me aclararía las cosas.

Supongamos que tengo un método que necesita pasar un objeto IEnumerable<String>. Todo lo que se necesita hacer es concatenar las letras roxxors al final de cada String en el iterador. A continuación, devolverá este nuevo iterador (por supuesto, el objeto original IEnumerable se deja como estaba).

¿Cómo podría hacerlo? La respuesta aquí debería ayudar a muchos con preguntas básicas sobre estos objetos además de mí, por supuesto.

Respuesta

78

Aquí está la documentación en IEnumerator. Se utilizan para obtener los valores de las listas, donde la longitud no se conoce necesariamente por adelantado (aunque podría ser). La palabra proviene del enumerate, lo que significa "contar o nombrar uno por uno".

IEnumerator y IEnumerator<T> se proporciona por todos IEnumerable y IEnumerable<T> las interfaces (este último proporcionando ambos) en NET a través de GetEnumerator(). Esto es importante porque la declaración foreach está diseñada para trabajar directamente con los enumeradores a través de esos métodos de interfaz.

Así, por ejemplo:

IEnumerator enumerator = enumerable.GetEnumerator(); 

while (enumerator.MoveNext()) 
{ 
    object item = enumerator.Current; 
    // Perform logic on the item 
} 

se convierte en:

foreach(object item in enumerable) 
{ 
    // Perform logic on the item 
} 

En cuanto a su situación específica, casi todas las colecciones en .NET implementan IEnumerable. Debido a eso, puede hacer lo siguiente:

public IEnumerator Enumerate(IEnumerable enumerable) 
{ 
    // List implements IEnumerable, but could be any collection. 
    List<string> list = new List<string>(); 

    foreach(string value in enumerable) 
    { 
     list.Add(value + "roxxors"); 
    } 
    return list.GetEnumerator(); 
} 
+0

Restablecer() no es llamado por foreach. Está destinado a la interoperabilidad COM, y no todos los enumeradores lo admiten (de hecho, la mayoría de los enumeradores * no * lo admiten). –

+0

Los enumeradores son de solo lectura, ¿correcto? ¿Cómo puedo devolver un tipo de enumerador que contiene mis modificaciones utilizando dicho patrón? – BlackVegetable

+0

@Martinho Tienes razón. –

5

me gustaría hacer algo como:

private IEnumerable<string> DoWork(IEnumerable<string> data) 
{ 
    List<string> newData = new List<string>(); 
    foreach(string item in data) 
    { 
     newData.Add(item + "roxxors"); 
    } 
    return newData; 
} 

Cosas simples :)

+0

Este fue mi primer pensamiento. Sin embargo, otros métodos con los que interactúo requieren que devuelva un tipo IEnumerable o somesuch. ¡Gracias por la respuesta! – BlackVegetable

+0

@BlackVegetable: 'List ' es un 'IEnumerable '. Pero sí, hay mejores formas de hacerlo (usando 'yield'). –

+1

Me parece recordar que debe intentar no devolver una Lista en un método declarado como IEnumerable. La razón es que las personas pueden "hacer trampa" y notar que en realidad es una lista y comenzar a hacer una lista con ella. List (y, de hecho, todos los IEnumerables) tiene un método AsEnumerable() que creo que debería llamarse y devolverse. – Chris

8

Si he entendido bien a continuación, en C# yield return la magia compilador es todo lo que necesita, creo.

p. Ej.

IEnumerable<string> myMethod(IEnumerable<string> sequence) 
{ 
    foreach(string item in sequence) 
    { 
     yield return item + "roxxors"; 
    } 
} 
+0

Entonces, ¿el rendimiento en este caso devolverá una única Cadena (modificada) de la lista cada vez que se ejecute? ¿O devolverá algún tipo de objeto IEnumerable? – BlackVegetable

+0

@BlackVegetable Sí, devolverá un objeto 'IEnumerable' que construirá una cadena cada vez que se invoca' MoveNext' (ya sea directa o indirectamente con foreach) –

+0

Sí, es azúcar sintáctico, le dice al compilador que lo convierta en un bloque iterador. Consulte aquí http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx –

12
public IEnumerable<string> Appender(IEnumerable<string> strings) 
{ 
    List<string> myList = new List<string>(); 
    foreach(string str in strings) 
    { 
     myList.Add(str + "roxxors"); 
    } 
    return myList; 
} 

o

public IEnumerable<string> Appender(IEnumerable<string> strings) 
{ 
    foreach(string str in strings) 
    { 
     yield return str + "roxxors"; 
    } 
} 

utilizando el yield construct, o simplemente

var newCollection = strings.Select(str => str + "roxxors"); //(*) 

o

var newCollection = from str in strings select str + "roxxors"; //(**) 

donde los dos últimos usan LINQ y (**) es solo azúcar sintáctico para (*).

+0

Patrón interesante con el LINQ. Tendré que investigar eso. ¡Gracias a todos por su (rápida) ayuda! – BlackVegetable

+0

Parece recordar que debe intentar no devolver una Lista en un método declarado como IEnumerable. La razón es que las personas pueden "hacer trampa" y notar que en realidad es una lista y comenzar a hacer una lista con ella. List (y, de hecho, todos los IEnumerables) tiene un método AsEnumerable() que creo que debería llamarse y devolverse. De lo contrario, la respuesta principal para el rendimiento y particularmente las respuestas de linq. :) – Chris

+0

Si planea hacer una gran cantidad de desarrollo en C#, definitivamente querrá invertir algo de tiempo en LINQ - le ahorrará mucho tiempo y le hará sentir mejor acerca de su código :-) – Rune

4

También se puede usar Seleccionar método de LINQ:

var source = new[] { "Line 1", "Line 2" }; 

var result = source.Select(s => s + " roxxors"); 

Lea más aquí Enumerable.Select Method