visual tipos studio structs example ejemplos datos array c# .net enumeration struct-vs-class

c# - tipos - Implementación del enumerador: ¿usa struct o class?



tipos de datos en c# visual studio (8)

Escríbelo usando yield return .

En cuanto a por qué, de lo contrario, podría elegir entre class o struct , si lo convierte en una struct entonces se coloca en un recuadro tan pronto como se devuelve como una interfaz, por lo que convertirlo en una struct solo provoca que se produzca una copia adicional. No puedo ver el punto de eso!

Observé que List<T> define su enumerador como una struct , mientras que ArrayList define su enumerador como una class . ¿Cual es la diferencia? Si voy a escribir un enumerador para mi clase, ¿cuál sería preferible?

EDITAR: Mis requisitos no se pueden cumplir con el yield , por lo que estoy implementando un enumerador propio. Dicho esto, me pregunto si sería mejor seguir las líneas de List<T> e implementarlo como una estructura.


La forma más fácil de escribir un enumerador en C # es con el patrón de "rendimiento devuelto". Por ejemplo.

public IEnumerator<int> Example() { yield return 1; yield return 2; }

Este patrón generará todo el código del enumerador debajo del capó. Esto toma la decisión de tus manos.


Un enumerador es intrínsecamente una estructura cambiante, ya que necesita actualizar el estado interno para pasar al siguiente valor en la colección original.

En mi opinión, las estructuras deberían ser inmutables, entonces usaría una clase.


Hay un par de publicaciones en el blog que cubren exactamente este tema. Básicamente, las estructuras del enumerador son una muy mala idea ...


Reason List utiliza un enumerador de struct para evitar la generación de basura en las instrucciones de foreach. Esta es una buena razón, especialmente si está programando para Compact Framework, porque CF no tiene GC generacional y CF generalmente se usa en hardware de bajo rendimiento donde puede conducir rápidamente a problemas de rendimiento.

Además, no creo que las estructuras mutables sean fuente de problemas en algunos ejemplos publicados, sino en programadores que no comprenden bien cómo funcionan los tipos de valores.


Cualquier implementación de IEnumerable<T> debería devolver una clase. Puede ser útil, por motivos de rendimiento, tener un método GetEnumerator que devuelva una estructura que proporcione los métodos necesarios para la enumeración, pero que no implemente IEnumerator<T> ; este método debería ser diferente de IEnumerable<T>.GetEnumerator , que luego debería implementarse explícitamente.

El uso de este enfoque permitirá un mejor rendimiento cuando la clase se enumere utilizando un bucle foreach o "For Each" en C # o vb.net o en cualquier contexto donde el código que está haciendo la enumeración sepa que el enumerador es una estructura, pero evite las trampas que de otro modo ocurrirían cuando el enumerador se encasilla y pasa por valor.


Al igual que otros, yo elegiría una clase. Las estructuras mutables son desagradables. (Y como sugiere Jared, usaría un bloque iterador. Codificar a mano un enumerador es complicado para hacerlo bien).

Vea este hilo para ver un ejemplo de que el enumerador de la lista es una estructura mutable que causa problemas ...


Para expandir en @Earwicker: generalmente es mejor que no escriba un tipo de enumerador, y en su lugar utilice el yield return para que el compilador lo escriba por usted. Esto se debe a que hay una serie de sutilezas importantes que podrías perder si lo haces tú mismo.

Vea la pregunta " ¿Cuál es la palabra clave de rendimiento utilizada en C #? " Para obtener más detalles sobre cómo usarla.

También Raymond Chen tiene una serie de publicaciones en el blog (" La implementación de iteradores en C # y sus consecuencias ": partes 1 , 2 , 3 y 4 ) que le muestran cómo implementar un iterador correctamente sin yield return , lo que muestra cuán complejo lo es, y por qué debería usar el yield return .