2011-03-02 8 views
7

Tengo una clase que implementa IEnumerator<string>. Vea a continuación:¿Por qué necesito IEnumerator.Current en una clase que implementa IEnumerator <T>?

public class MyClass : IEnumerator<string> 
{ 
    public bool MoveNext() 
    { 
     //.... 
    } 

    //Implement other required methods.... 

    //Confusion lies below: 
    public string Current { get { return this.CurrentLine; } } 

    //Why do I need to implement IEnumerator.Current?! In my tests, it's not even called during my iteration 
    object IEnumerator.Current { get { throw new NotImplementedException(); } } 

} 

Además del hecho de que la propiedad .Current existe tanto en la interfaz y la interfaz IEnumerator<T>IEnumerator (que hereda IEnumerator<T>), ¿cuál es el punto de aplicación? Como se ve arriba, ni siquiera se llama.

Respuesta

15

IEnumerator<T> implementa IEnumerator, por lo que en el nivel más básico debe cumplir el contrato.

Específicamente en cuanto a porqué - Qué pasa si alguien hace esto:

((IEnumerator)yourInstance).Current 

Ellos (por lo general) debe esperar para obtener una copia mecanografiada débilmente del mismo valor/referencia de regresar de aplicación IEnumerator<T> 's. Así que en la mayoría de los casos, simplemente volver this.Current y no se preocupe por él :)

(FYI - volver this.Current también es una buena práctica porque sigue seco y SRP - dejar que la versión inflexible de tipos del actual acuerdo con los detalles de implementación de lo actual es en realidad.)

+0

+1 para dar un ejemplo de cómo se podría llamar a la implementación de IEnumerator.Current en este caso. – contactmatt

3

La razón es que hereda IEnumerator<T>IEnumerator por lo que cuando se hereda de forma implícita IEnumerator<T> que también heredan de IEnumerator. Si publicita una interfaz, también debe proporcionar una implementación para esa interfaz, incluso si nunca tiene la intención de usarla.

1

El compilador requiere que implemente todos los virtuales, ya que posiblemente no pueda conocer a cuáles se llamará cuando algún ensamblaje imprevisto cargue su ensamblaje en algún momento en el futuro desconocido. Al heredar de una interfaz, está "firmando un contrato" que promete implementar a todos sus miembros. El compilador lo retiene en ese acuerdo para que otros ensambles puedan confiar en él.

El objetivo de la función de interfaz es permitir que su clase indique a cualquier otro ensamblaje, en cualquier lugar, en cualquier momento, "esto es lo que puede pedirme que haga". Si desea anunciar una capacidad menor, defina una nueva interfaz que proporcione solo la funcionalidad parcial que desee e impleméntela.

Por supuesto, todo esto es algo de fuerza industrial. Es más de lo que necesita para su código en este momento. Pero C# está destinado a ser útil para hacer cosas serias, no solo juguetes.

En cuanto a las dos anulaciones diferentes, casi idénticas: Debe anular ambas propiedades actuales porque son esencialmente diferentes: una es una T que retorna genérica; el otro es un Objeto que retorna no genérico. Siempre puede tratar una referencia de Cadena como una referencia a Objeto, pero eso no funciona en ambos sentidos. Y luego, ¿qué pasa con los tipos de valor? T no está obligado a ser una clase. Claro, el compilador hipotéticamente podría resolver todo esto por ti y liberarte del peligro en los casos en que los dos son fungibles, pero no es así, y no estoy convencido de que así sea. Si quieres C++, sabes dónde encontrarlo.

Cuestiones relacionadas