Question

C’est peut-être une vieille question: pourquoi IEnumerable < T > hérite-t-il de IEnumerable ?

C’est ce que fait NET, mais cela pose quelques problèmes. 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 de IList.

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

Était-ce utile?

La solution

tout droit sorti de la bouche du cheval (Hejlsberg) :

  

Idéalement, toutes les interfaces de collection génériques (par exemple, ICollection < T > , IList < T > ) hériteraient de leurs contreparties non génériques telles que des instances d'interface génériques pourraient être utilisé à la fois avec du code générique et non générique. Par exemple, il serait pratique de laisser un IList < T > au code qui attend un IList .

     

Il s’avère que la seule interface générique pour laquelle cela est possible est IEnumerable < T > , car seul IEnumerable < T / gt; est une variante contraire: In < code> IEnumerable < T > , le paramètre de type T est utilisé uniquement dans les "sorties". positions (valeurs de retour) et non dans "entrée". positions (paramètres). ICollection & Lt; T > et IList & Lt; T > utilisent T dans les positions d'entrée et de sortie. Ces interfaces sont donc invariantes. (En passant, ils auraient été opposés à la variante si T était utilisé uniquement dans les positions d'entrée, mais cela n'a pas vraiment d'importance ici.)

     

< ... snip ... >

Donc, pour répondre à votre question, IEnumerable < T > hérite de IEnumerable car il le peut! : -)

Autres conseils

La réponse pour IEnumerable est: "car elle peut sans affecter la sécurité du type".

IEnumerable est un " en lecture seule " interface - donc peu importe que la forme générique soit plus spécifique que la forme non générique. Vous ne cassez rien en implémentant les deux. IEnumerator.Current renvoie objet , alors que IEnumerator < T > .Current renvoie T - c'est correct, comme vous le pouvez toujours légitimement convertir en objet , bien que cela puisse signifier boxe.

Comparez ceci avec IList < T> et IList - vous pouvez appeler Add (objet) sur un IList , alors que cela pourrait bien ne pas être valide pour un IList < T > particulier (autre que IList < objet > en fait).

de bloguer avec la réponse d'Anders à propos de la réponse de Anders cette question même.

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

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

J'implémente généralement une méthode privée qui renvoie un énumérateur, puis le passe à la fois pour l'ancien et le nouveau style GetEnumerator.

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

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

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

C’est pour que cela fonctionne 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 faire des choses comme cast IList < long > comme IList < int > ;, des versions non génériques d’interfaces peuvent donc s’avérer très utiles lorsque vous avez besoin d’une classe ou d’une interface de base fixe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top