Pregunta

Esta podría ser una vieja pregunta: ¿por qué IEnumerable < T > se hereda de IEnumerable ?

Así es .NET, pero trae un pequeño problema. Cada vez que escribo una clase implementa IEumerable < T > , tengo que escribir dos funciones GetEnumerator () , una para IEnumerable < T > y el otro para IEnumerable .

Y, IList < T > no hereda de IList.

No sé por qué IEnumerable < T > está diseñado de otra manera.

¿Fue útil?

Solución

Directamente desde la boca del caballo (Hejlsberg) :

  

Idealmente, todas las interfaces de recopilación genéricas (por ejemplo, ICollection < T > , IList < T > ) heredarían de sus contrapartes no genéricas, de modo que las instancias de interfaz genéricas podrían Ser utilizado tanto con código genérico como no genérico. Por ejemplo, sería conveniente si se pasara un IList < T > al código que espera un IList .

     

Resulta que la única interfaz genérica para la que es posible es IEnumerable < T > , porque solo IEnumerable < T > es contra-variante: In < código> IEnumerable < T > , el parámetro de tipo T se usa solo en la salida " " posiciones (valores de retorno) y no en " entrada " Posiciones (parámetros). ICollection < T > e IList < T > usan T en las posiciones de entrada y salida, y esas interfaces son invariantes. (Dejando de lado, habrían sido contra-variante si T se usara solo en las posiciones de entrada, pero eso realmente no importa aquí).

     

< ... recorte ... >

Entonces, para responder a su pregunta, IEnumerable < T > se hereda de IEnumerable porque puede! :-)

Otros consejos

La respuesta para IEnumerable es: " porque puede sin afectar el tipo de seguridad " ;.

IEnumerable es un " readonly " interfaz - por lo que no importa que la forma genérica sea más específica que la forma no genérica. No rompes nada implementando ambos. IEnumerator.Current devuelve objeto , mientras que IEnumerator < T > .Current devuelve T . Está bien, como puede siempre convertir legítimamente a objeto , aunque puede significar boxeo.

Compare esto con IList < T > e IList - puede llamar a Add (objeto) en un IList , mientras que eso puede no ser válido para cualquier IList < T > en particular (cualquier otra cosa que no sea IList < object > de hecho).

blogged de Brad Abram con la respuesta de Anders sobre esta misma pregunta.

Es para compatibilidad con versiones anteriores. Si llama a una función .Net 1.1 que espera un IEnumerable de vainilla, puede pasar su IEnumerable genérico.

Luckilly el IEnumerator genérico hereda del IEnumerator de estilo antiguo

Por lo general implemento un método privado que devuelve un enumerador y luego lo paso tanto para el método GetEnumerator del estilo antiguo como del nuevo.

    private IEnumerator<string> Enumerator() {
        // ...
    }

    public IEnumerator<string> GetEnumerator() {
        return Enumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return Enumerator();
    }

Esto es para que funcione con clases que no admiten genéricos. Además, los genéricos de .NET no te permiten hacer cosas como IList < long > como IList < int > ;, las versiones no genéricas de interfaces pueden ser bastante útiles cuando necesita una clase o interfaz base fija.

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