Question

Quelle est la différence entre IEnumerable et IEnumerable<T>?

J'ai vu de nombreuses classes de framework implémenter ces deux interfaces, donc je voudrais savoir quels avantages que l'on obtient en mettant en œuvre les deux?

Veuillez voir comment ils ont été définis:

public interface IEnumerable
{
    [DispId(-4)]
    IEnumerator GetEnumerator();
}
public interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

Comme nous le voyons, IEnumerable<T> dérive de IEnumerable, ça veut dire quoi que ce soit IEnumerable a, IEnumerable<T> hérite, alors pourquoi implémentons-nous les deux au lieu de simplement IEnumerable<T>? La mise en œuvre IEnumerable<T> pas assez?

De même, il y a d'autres paires similaires:

  • IList et IList<T>
  • ICollection et ICollection<T>

J'aimerais aussi les savoir.

Était-ce utile?

La solution

Fondamentalement, les interfaces non congéniques sont venues en premier, dans .NET 1.0 et 1.1. Puis, lorsque .NET 2.0 est sorti, les équivalents génériques sont sortis. La vie aurait été beaucoup plus simple si les génériques en avaient été transformés en .NET 1.0 :)

En termes de mise en œuvre "seulement" IEnumerable<T> au lieu des deux - vous ont Pour implémenter les deux, et vous devez également utiliser une implémentation d'interface explicite, étant donné que les deux définissent un paramètre sans paramètre GetEnumerator méthode. Comme IEnumerator<T> prolongement IEnumerator aussi, c'est normalement quelque chose comme ça:

public IEnumerator<T> GetEnumerator()
{
    // Return real iterator
}

// Explicit implementation of nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
    // Delegate to the generic implementation
    return GetEnumerator();
}

D'un autre côté, avec les blocs d'itérateur introduits en C # 2 (avec yield return etc) Vous avez rarement besoin de mettre en œuvre ces choses entièrement à la main, heureusement. Vous devrez peut-être écrire quelque chose comme ce qui précède, puis utiliser yield return dans le GetEnumerator méthode.

Notez que IList<T> Est-ce que ne pas se déployer IList, et ICollection<T> Est-ce que ne pas se déployer ICollection. C'est parce qu'il est moins sécurisé pour le faire ... alors que tout itérateur générique peut être considéré comme un itérateur non congénérique en raison de la conversion (potentiellement de boxe) de toute valeur en object, IList et ICollection Autoriser les valeurs ajoutée à la collection; Et il n'a pas de sens d'ajouter (dire) une chaîne à un IList<int>.

Edit: la raison pour laquelle nous avons besoin IEnumerable<T> est pour que nous puissions itérer de manière sécurisée et propager ces informations autour. Si je retourne un IEnumerable<string> Pour vous, vous savez que vous pouvez supposer en toute sécurité que tout ce qui est renvoyé sera une référence de chaîne ou null. Avec IEnumerable, nous avons dû lancer efficacement (souvent implicitement dans un foreach instruction) chaque élément qui a été renvoyé de la séquence, car le Current propriété de IEnumerator est juste de type object. Quant à pourquoi nous toujours besoin IEnumerable - Parce que les vieilles interfaces ne disparaissent jamais, en gros. Il y a trop de code existant qui l'utilise.

Ça aurait été possible pour IEnumerable<T> ne pas s'étendre IEnumerable, mais alors tout code souhaitant utiliser un IEnumerable<T> ne pouvait pas appeler une méthode acceptant IEnumerable - Et il y avait beaucoup de méthodes comme celle de .NET 1.1 et 1.0.

Autres conseils

L'un renvoie un objet de type objet, l'autre renvoie un objet de type T.

Quant à savoir pourquoi vous voyez des classes définissant les deux, assez bien que iEnumerable <T> implémente ienumerable, ce n'est pas nécessaire mais c'est bien dans une auto-documentation pour indiquer les sous-interfaces parfois. Envisager

interface IA { }
interface IB : IA { }

class A : IB {} // legal, IB implements IA

class B : IA, IB {} // also legal, possible more clear on intent

Tout en itérant à travers la boucle, l'iénumerateur maintient l'état. Il se souvient de la position du curseur et non.

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