Sería C# beneficiarse de las distinciones entre los tipos de los enumeradores, como C++ iteradores?

StackOverflow https://stackoverflow.com/questions/1634934

  •  06-07-2019
  •  | 
  •  

Pregunta

He estado pensando acerca de la IEnumerator.Reset() método.He leído en la documentación de MSDN que sólo existe para la interoperabilidad COM.Como un programador de C++ que a mí me parece un IEnumerator que apoya Reset es lo que yo llamaría una adelante iterador, mientras que un IEnumerator que no admite Reset es realmente un iterador de entrada.

Así que la primera parte de mi pregunta es, es esto correcto entendimiento?

La segunda parte de mi pregunta es, ¿sería de ningún beneficio en C# si no se hace una distinción entre la entrada de los iteradores y adelante iteradores (o "enumeradores" si se prefiere)?No es ayudar a eliminar la confusión entre los programadores, como el que se encuentra en este ASÍ que la pregunta sobre la clonación de los iteradores?

EDITAR:Aclaración en adelante y entrada de los iteradores.Un iterador de entrada sólo garantiza que usted puede enumerar a los miembros de una colección (o de un generador de función o de un flujo de entrada) sólo una vez.Esto es exactamente cómo IEnumerator obras en C#.Si o no usted puede enumerar una segunda vez, es determinado por el si o no Reset es compatible.Un avance del iterador, no tiene esta restricción.Usted puede enumerar más de los miembros como a menudo como usted quiere.

Un poco de C# programadores no comprender por qué un IEnumerator no puede ser estimado de manera fiable utilizado en un multipass algoritmo.Considere el siguiente caso:

void PrintContents(IEnumerator<int> xs)
{
  while (iter.MoveNext())
    Console.WriteLine(iter.Current); 
  iter.Reset();
  while (iter.MoveNext())
    Console.WriteLine(iter.Current); 
}

Si llamamos PrintContents en este contexto, no hay problema:

List<int> ys = new List<int>() { 1, 2, 3 }
PrintContents(ys.GetEnumerator()); 

Sin embargo mira el siguiente:

IEnumerable<int> GenerateInts() {   
  System.Random rnd = new System.Random();
  for (int i=0; i < 10; ++i)
    yield return Rnd.Next();
}

PrintContents(GenerateInts());

Si el IEnumerator compatible Reset, en otras palabras , se admite multi-pass de algoritmos, cada vez que se procesa la colección que iba a ser diferente.Este sería indeseable, porque sería sorprendente comportamiento.Este ejemplo es un poco fingido, sino que se produce en el mundo real (por ejemplo,la lectura de secuencias de archivo).

¿Fue útil?

Solución

Pregunta interesante. Mi opinión es que, por supuesto, C # se beneficiaría . Sin embargo, no sería fácil agregarlo.

La distinción existe en C ++ debido a su sistema de tipos mucho más flexible. En C #, no tiene una forma genérica robusta para clonar objetos, que es necesaria para representar iteradores hacia adelante (para admitir la iteración de múltiples pasos). Y, por supuesto, para que esto sea realmente útil, también necesitaría admitir iteradores / enumeradores bidireccionales y de acceso aleatorio. Y para que todos funcionen sin problemas, realmente necesita algún tipo de escritura de pato, como las plantillas de C ++.

Finalmente, los alcances de los dos conceptos son diferentes.

En C ++, se supone que los iteradores representan todo lo que necesita saber sobre un rango de valores. Dado un par de iteradores, no necesito el contenedor original. Puedo ordenar, buscar, manipular y copiar elementos tanto como quiera. El contenedor original está fuera de la imagen.

En C #, los enumeradores no están destinados a hacer tanto. En última instancia, están diseñados para permitirle recorrer la secuencia de manera lineal.

En cuanto a Reset(), es ampliamente aceptado que fue un error agregarlo en primer lugar. Si funcionó y se implementó correctamente, entonces sí, podría decir que su enumerador fue análogo a los iteradores de reenvío, pero en general, es mejor ignorarlo como un error. Y luego todos los enumeradores son similares solo a los iteradores de entrada.

Desafortunadamente.

Otros consejos

Reset fue un gran error.Yo llame travesuras en Reset.En mi opinión, la forma correcta para reflejar la distinción que están haciendo entre "adelante iteradores" y "iteradores de entrada" en la .NET tipo de sistema es la diferencia entre el IEnumerable<T> y IEnumerator<T>.

Ver también esta respuesta, donde Microsoft Eric Lippert (en una no oficial capactiy, sin duda, mi punto es que alguien con más credenciales que tengo que hacer la afirmación de que este fue un error de diseño) se convierte en un punto similar en los comentarios.También ver también su impresionante blog.

Viniendo desde la perspectiva de C #:

Casi nunca usas IEnumerator directamente. Usualmente haces una declaración foreach, que espera un IEnumerable.

IEnumerable _myCollection;
...
foreach (var item in _myCollection) { /* Do something */ }

Tampoco pasa Reset(). Si desea pasar una colección que necesita iteración, pase <=>. Dado que <=> tiene una única función, que devuelve un <=>, se puede usar para iterar la colección varias veces (múltiples pases).

No hay necesidad de una función <=> en <=> porque si desea comenzar de nuevo, simplemente deseche la antigua (basura recolectada) y obtenga una nueva.

El .NET framework se beneficiarían enormemente si hay un medio de preguntar a un IEnumerator<T> acerca de qué habilidades se podría apoyar y lo que promete lo podría hacer.Tales características también sería útil en IEnumerable<T>, pero ser capaz de hacer las preguntas de un enumerador permitiría código que puede recibir un enumerador de contenedores como ReadOnlyCollection para utilizar el subyacente de la colección en mejorar las formas sin tener que involucrar a la envoltura.

Dado cualquier enumerador para una colección que es capaz de ser enumerado en su totalidad y no es demasiado grande, se podría producir a partir de un IEnumerable<T> que siempre dan la misma secuencia de elementos (específicamente el conjunto de elementos que quedan en el enumerador) por la lectura de todo su contenido a una matriz, eliminación y descartando el enumerador, y obtener un enumeradores de la matriz (el uso de que en lugar de la original abandonados enumerador), envolviendo la matriz en un ReadOnlyCollection<T>, y regreso.Aunque este enfoque podría funcionar con cualquier tipo de colección enumerable de cumplir con los criterios anteriores, sería terriblemente ineficiente con la mayoría de ellos.Tener un medio de preguntar a un enumerador para producir su contenido restante en una inmutable IEnumerable<T> permitiría a muchos tipos de enumeradores para llevar a cabo la indicada acción de manera mucho más eficiente.

No lo creo. Llamaría a IEnumerable un iterador directo y un iterador de entrada. No le permite ir hacia atrás ni modificar la colección subyacente. Con la adición de la palabra clave foreach, la mayoría de las veces, los iteradores casi no se piensan.

Opinión: La diferencia entre los iteradores de entrada ( obtener cada uno ) frente a los iteradores de salida ( hacer algo a cada uno ) es demasiado trivial para justificar una adición al marco. Además, para hacer un iterador de salida, deberá pasar un delegado al iterador. El iterador de entrada parece más natural para los programadores de C #.

También hay IList<T> si el programador quiere acceso aleatorio.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top