67 votes

Pourquoi ne IEnumerable<T>.ToList<T>() retourne la Liste<T> au lieu de IList<T>?

La méthode d'extension ToList() renvoie un List<TSource>. Suivant le même schéma, ToDictionary() renvoie un Dictionary<TKey, TSource>.

Je suis curieux de savoir pourquoi ces méthodes ne sont pas de type de leurs valeurs de retour en tant que IList<TSource> et IDictionary<TKey, TSource> respectivement. Cela semble même étrangeté parce qu' ToLookup<TSource, TKey> types de sa valeur de retour comme une interface au lieu d'une mise en œuvre effective.

En regardant la source de ces méthodes d'extension à l'aide de dotPeek ou d'autres decompiler, nous voyons la suite de la mise en œuvre (montrant ToList() parce que c'est plus court):

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { 
   if (source == null) throw Error.ArgumentNull("source");
   return new List<TSource>(source); 
}

Alors pourquoi ce type de méthode de sa valeur de retour comme une mise en œuvre spécifique de l'interface et non pas l'interface elle-même? Le seul changement serait le type de retour.

Je suis curieux parce que l' IEnumerable<> extensions sont très cohérents dans leurs signatures, à l'exception de ces deux cas. J'ai toujours pensé que c'est un peu étrange.

En outre, pour rendre les choses encore plus confuses, la documentation pour ToLookup() membres de:

Crée une liste de choix à partir d'un IEnumerable selon un clé spécifiée sélecteur de fonction.

mais le type de retour est - ILookup<TKey, TElement>.

Dans Edulinq, Jon Skeet mentionne que le type de retour est - List<T> au lieu de IList<T>, mais ne touche pas le sujet.
Vaste de la recherche a donné aucune réponse, donc ici je vous demande:

Est-il une décision de conception derrière pas taper les valeurs de retour comme les interfaces, ou est-ce juste un hasard?

49voto

hvd Points 42125

De retour List<T> a l'avantage de ces méthodes d' List<T> qui ne font pas partie de l' IList<T> sont facilement utilisables. Il y a beaucoup de choses que vous pouvez faire avec un List<T> que vous ne pouvez pas faire avec une IList<T>.

En revanche, Lookup<TKey, TElement> a une seule méthode disponible qu' ILookup<TKey, TElement> n'ont pas (ApplyResultSelector), et vous ne serait probablement pas fin à l'aide de qui, de toute façon.

12voto

Matías Fidemraizer Points 16842

Ces types de décisions peuvent se sentir arbitraire, mais je suppose que c' ToList() retours List<T> plutôt que d'une interface, car List<T> deux implémente IList<T> mais il ajoute d'autres membres qui ne sont pas présents dans une régulière, IList<T>-tapé objet.

Par exemple, AddRange().

Voir ce qu' IList<T> devrait mettre en œuvre (http://msdn.microsoft.com/en-us/library/5y536ey6.aspx):

public interface IList<T> : ICollection<T>, 
    IEnumerable<T>, IEnumerable

Et List<T> (http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx):

public class List<T> : IList<T>, ICollection<T>, 
    IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, 
    IEnumerable

Peut-être votre propre code ne nécessite pas d' IReadOnlyList<T>, IReadOnlyCollection<T> ou ICollection, mais d'autres composants .NET Framework et d'autres produits peut s'appuyer sur des objets de la liste et c'est pourquoi .NET de l'équipe de développement a décidé de ne pas renvoyer une interface.

Ne se sentent pas toujours de retour d'une interface est la meilleure pratique. C'est si votre code ou de tiers exigent une telle encapsulation.

8voto

Servy Points 93720

Il y a un certain nombre d'avantages pour peu d'avoir un List sur un IList. Pour commencer, List a des méthodes qui IList ne le sont pas. Vous aussi de savoir ce que la mise en œuvre est ce qui vous permet de raisonner sur comment il va se comporter. Vous savez qu'il peut efficacement à ajouter à la fin, mais pas le début, vous savez que c'est de l'indexeur est très rapide, etc.

Vous n'avez pas besoin de vous soucier de votre structure à modifier LinkedList et de secours et les performances de votre application. Quand il s'agit de structures de données comme cela, il est vraiment important dans beaucoup de contextes de savoir comment votre structure de données est mis en œuvre, non seulement le contrat qu'il suit. C'est un comportement qui ne devrait jamais changer.

Vous aussi vous ne pouvez pas passer un IList pour une méthode d'accepter un List, ce qui est quelque chose que vous voyez beaucoup de. ToList est fréquemment utilisé parce que la personne a vraiment besoin d'une instance de List, pour correspondre à une signature il ne peut pas contrôler, et IList n'aide pas.

Ensuite, nous nous demandons quels avantages il y a à revenir IList. Eh bien, nous pourrions peut-être revenir à l'autre de la mise en œuvre d'une liste, mais comme mentionné précédemment, cette situation est probablement très conséquences néfastes, presque certainement beaucoup plus que ce que pourrait éventuellement être obtenue à partir de l'utilisation de tout autre type. Il peut vous donner d'affinité à l'aide d'une interface au lieu d'une mise en œuvre, mais même ça, c'est quelque chose que je ne ressens pas une bonne mentalité (en général ou) dans ce contexte. Comme une règle de retour d'une interface est généralement préférable de ne pas renvoyer une mise en œuvre concrète. "Être libéral dans ce que vous acceptez et précis dans ce que vous fournissez." Les paramètres de vos méthodes devraient, si possible, être interfaces définissant le moins de fonctionnalités dont vous avez besoin pour que votre interlocuteur peut passer de la mise en application qui fait ce que vous avez besoin, et vous devez fournir le béton d'une mise en œuvre en l'appelant est "autorisé" à voir ce qu'ils peuvent faire autant avec le résultat que l'objet est capable de faire. En passant une interface est la restriction de cette valeur, qui est seulement de temps en temps quelque chose que vous voulez faire.

Alors maintenant, nous nous déplaçons sur, "Pourquoi revenir ILookup et pas Lookup?" Tout d'abord, Lookup n'est pas une classe publique. Il n'y a pas d' Lookup en System.Collections.*. L' Lookup classe qui est exposé via LINQ expose pas les constructeurs publiquement. Vous n'êtes pas en mesure d'utiliser la classe sauf par le biais d' ToLookup. Il expose également aucune fonctionnalité qui n'est pas déjà exposées par le biais ILookup. Dans ce cas particulier, ils ont conçu l'interface spécifiquement autour de cette méthode exacte (ToLookup) et l' Lookup classe est une classe spécialement conçu pour implémenter cette interface. Pour tout cela, pratiquement tous les points discutés à propos de List il suffit de ne pas s'appliquer ici. Aurait-il été un problème pour revenir Lookup plutôt non, pas vraiment. Dans ce cas, il vraiment n'est tout simplement pas beaucoup d'importance à tous les deux de toute façon.

6voto

À mon avis, retour d'un List<T> est justifiée par le fait que le nom de la méthode, dit - ToList. Sinon il faudrait être nommé ToIList. C'est le but de cette méthode pour convertir un non spécifique IEnumerable<T> pour le type spécifique List<T>.

Si vous aviez une méthode avec une différence de nom comme l' GetResults, puis un type de retour comme IList<T> ou IEnumerable<T> me semblerait opportun.


Si vous regardez à la mise en œuvre de l' Lookup<TKey, TElement> classe avec réflecteur, vous verrez beaucoup de internal des membres, qui ne sont accessibles que LINQ lui-même. Il n'y a pas de constructeur public et Lookup des objets sont immuables. Par conséquent, il n'y aurait aucun avantage à exposer Lookup directement.

Lookup<TKey, TElement> de la classe semble être une sorte de LINQ-interne et n'est pas destiné à un usage public.

3voto

Robert Points 1649

En général, lorsque vous appelez ToList() sur une méthode, vous êtes à la recherche d'un type concret sinon, la question pourrait rester comme type IEnumerable. Vous n'avez pas besoin de convertir une Liste, sauf si vous faites quelque chose qui nécessite une liste concrète.

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