2010-03-25 15 views
5

¿Es esta una mala idea?IEnumerable e IEnumerator en la misma clase, ¿mala idea?

Private Class GH_DataStructureEnumerator(Of Q As Types.IGH_Goo) 
    Implements IEnumerable(Of Q) 
    Implements IEnumerator(Of Q) 
    .... 
    .... 
    'Current, MoveNext, Reset etc.' 
    .... 
    .... 

    Public Function GetEnumerator_Generic() As IEnumerator(Of Q) _ 
        Implements IEnumerable(Of Q).GetEnumerator 
    Return Me 
    End Function 
End Class 

Esta clase sólo es visible como un IEnumerable (Of T) Propiedad de sólo lectura, y me ahorra una clase adicional que envuelve IEnumerator (Of T). Pero de alguna manera, parece estar mal. ¿Hay una mejor manera?

Respuesta

4

Esta es una mala idea porque la solución se descompondrá si alguien intenta enumerar su colección más de una vez al mismo tiempo.

Por ejemplo: Esto romperá de alguna manera

For Each cur1 in yourObj 
    For Each cur2 in yourObj 
    Console.WriteLine("{0} - {1}", cur1,cur2) 
    Next 
Next 
+2

O incluso no al mismo tiempo, muy posiblemente :) –

+0

@Jon ¡muy cierto! – JaredPar

5

Definitivamente una mala idea. En particular, significa que dos llamadas a GetEnumerator devolverán referencias al mismo objeto, cuando deberían devolver iteradores independientes.

Dicho esto, el compilador de C# generará clases que implementarán ambos tipos si usa bloques de iterador ... pero hace todo lo posible para asegurarse de hacerlo bien. Le sugiero que no se someta a ese dolor :)

+0

Jon, el objetivo de mi vida es evitar el dolor, gracias por la información. –

1

De Implementing IEnumerable:

proporcionan un método GetEnumerator() que devuelve una estructura pública anidada llamados “enumerador” .

Por cierto, este sitio web es mantenido por Brad Abrams - uno de los autores de Framework Design Guidelines.

+0

Nunca me ha gustado esta sugerencia en particular: alienta las estructuras mutables, que pueden comportarse de manera malvada. –

+1

@Jon - Ese es un buen punto, pero creo que en este caso no es la peor idea. Definitivamente es una compensación entre el rendimiento (menos presión de memoria con una estructura) y tener una estructura mutable que podría introducir problemas en la aplicación. Creo que dado el hecho de que la mayoría de los desarrolladores no trabajan con la instancia del enumerador directamente, tenerla como una estructura mutable es una buena compensación para el beneficio del rendimiento. Pero, en general, estoy de acuerdo con que las estructuras mutables deberían evitarse. –

+0

Brad hace que la compensación sea muy clara: la implementación de este patrón implica tener un tipo público adicional (el Enumerador) y varios métodos públicos adicionales que realmente existen solo por razones de infraestructura. Estos tipos se suman a la complejidad percibida de la API y deben documentarse, probarse, versionarse, etc. ** Como tal, este patrón solo debe seguirse cuando el rendimiento es primordial. ** En consecuencia, esto * no * se debe usar la mayor parte del tiempo donde el rendimiento no es demasiado crítico. –

Cuestiones relacionadas