39 votes

Pourquoi IEnumerable <T> hériter de IEnumerable?

Cela pourrait être une vieille question: pourquoi IEnumerable<T> hérite-t-il de IEnumerable ?

C'est comme ça que fait .NET, mais cela pose un petit problème. Chaque fois que j'écris une classe implémente IEumerable<T> , je dois écrire deux fonctions GetEnumerator() , une pour IEnumerable<T> et l'autre pour IEnumerable .

Et, IList<T> n'hérite pas d'IList.

Je ne sais pas pourquoi IEnumerable<T> est conçu d'une autre manière.

51voto

Mark Brackett Points 46824

Straight from the horse's mouth (Hejlsberg):

Idéalement, tous les génériques de la collecte des interfaces (par exemple, ICollection<T>, IList<T>) héritent de leur non-générique homologues tels que l'interface générique instances pourrait être utilisé à la fois génériques et non génériques de code. Par exemple, il serait pratique si un IList<T> pourrait être transmis à un code qui s'attend à une IList.

Comme il s'avère, la seule interface générique pour lesquelles cela est possible est - IEnumerable<T>, parce que seul l' IEnumerable<T> est contre-variante: En IEnumerable<T>, le paramètre de type T est utilisé que dans la "sortie" des postes (les valeurs de retour) et non pas dans "l'entrée" des postes (paramètres). ICollection<T> et IList<T> d'utilisation T en entrée et en sortie des postes, et les interfaces sont donc invariant. (En aparté, ils auraient été contre-variante si T a été utilisé uniquement dans des positions d'entrée, mais qui n'a pas vraiment d'importance ici).

<...snip...>

Donc, pour répondre à votre question, IEnumerable<T> hérite IEnumerable parce qu'il peut! :-)

18voto

Jon Skeet Points 692016

La réponse pour IEnumerable est: "parce qu'il peut sans affecter la sécurité de type".

IEnumerable est un "readonly" - interface de sorte qu'il n'a pas d'importance que la forme générique est plus spécifique que le nongeneric forme. Vous ne cassez rien, par la mise en œuvre à la fois. IEnumerator.Current retours object, alors que IEnumerator<T>.Current retours T - c'est bien, comme vous pouvez toujours légitimement convertir object, même si cela peut signifier la boxe.

A comparer avec IList<T> et IList - vous pouvez appeler Add(object) sur IList, alors que c'est peut-être pas valide pour n'importe quel particulier, IList<T> (autre chose que de l' IList<object> en fait).

Brad Abram blogué avec Anders " réponse sur cette question.

3voto

Mendelt Points 21583

C'est pour la compatibilité descendante. Si vous appelez une fonction .Net 1.1 qui attend un IEnumerable vanille, vous pouvez passer votre IEnumerable générique.

Heureusement, le IEnumerator générique hérite de l'ancien IEnumerator

J'implémente généralement une méthode privée qui renvoie un énumérateur, puis je la transmets à la fois pour l'ancienne et la nouvelle méthode GetEnumerator.

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

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

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

2voto

jezell Points 2430

C'est ainsi qu'il fonctionnera avec des classes qui ne prennent pas en charge les génériques. De plus, les génériques .NET ne vous permettent pas de convertir IList <long> en IList <int>, les versions non génériques des interfaces peuvent donc être très utiles lorsque vous avez besoin d'une classe ou d'une interface de base fixe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X