1
votes

Pourquoi utiliser ICollection <T> sur IList <T>?

J'ai lu des articles qui disent utiliser ICollection<T> si vous voulez la fonctionnalité de IEnumerable<T> , mais aussi la propriété Count .

Cependant, puisque les méthodes d'extension de System.Linq.Enumerable fournissent des méthodes telles que ElementAt() , pourquoi n'utiliseriez-vous pas simplement un IList<T> place, puisque cela utilise un indexeur?

Il me semble que ICollection<T> peut faire ce que IList<T> peut faire, juste d'une manière beaucoup plus verbeuse et moins lisible.

Quel scénario serait-il plus lisible / plus efficace, plus adhérant aux principes SOLID, ou comment mieux utiliser ICollection<T> sur IList<T> ?

ÉDITER:

Les réponses à la question en double ne répondent pas à ma question car elles évitent de parler du fait ICollection<T> peut faire ce que IList<T> fait mais d'une manière beaucoup plus laide.

S'ils font tous les deux la même chose, pourquoi ne pas simplement utiliser le nettoyeur IList<T> ?

J'ai reçu de bien meilleures réponses ici: https://www.reddit.com/r/csharp/comments/dl9xao/why_use_icollectiont_over_ilistt/


10 commentaires

Vous dites donc que je peux appeler votre méthode ou lire votre propriété, récupérer une liste, puis commencer à y ajouter des éléments?


Les 3 types impliqués dans votre question me disent des choses différentes. IEnumerable me dit que j'obtiendrai une collection d'articles. ICollection me dit que j'obtiendrai une collection d'articles qui garantira un accès facile et rapide au nombre d'articles qu'il contient. La liste me dit que j'obtiendrai une collection que je pourrai manipuler. Vous devrez décider quel niveau est approprié dans chaque cas.


Mais ICollection vous offre une collection que vous pouvez également manipuler. ICollection semble avoir toutes les mêmes fonctionnalités que IList, mais pas aussi propre.


Malheureusement, je pense que cette question est hors sujet car elle sollicite indirectement l'opinion et la suggestion des gens. Il n'y a pas de réponse unique et solide fixe qui dit "retournez ceci alors que sinon cette autre chose". J'ai plusieurs opinions sur la question de savoir si vous devez retourner l'un ou l'autre, en fonction de nombreux facteurs, mais cela se résume à mes opinions.


Vous avez raison, mais il n'est pas nécessaire que ce soit une liste. Cela peut être quelque chose d'autre qui vous permet de le manipuler. Je suppose que je l'ai confondu avec IReadOnlyCollection qui est celui que j'utilise, désolé pour cela.


Où dois-je aller pour poser une question qui implique de recueillir l'opinion des gens?


Copie possible de 'IList' retourné vs 'ICollection' vs 'Collection'


Pour obtenir l'opinion des gens, je pense toujours que les salons de discussion ici résoudraient ce problème. Il y a peut-être d'autres sites sur le réseau qui le gèrent mieux, mais j'ai tendance à aller dans les salles de discussion. Vous pouvez les trouver en haut à droite dans le petit bouton Stack Exchange.


Mon opinion sur les types impliqués est que vous devez être aussi ouvert que possible dans les paramètres / positions d'entrée, ce qui signifie favoriser IEnumerable sur ICollection / List, et aussi explicite que possible dans les paramètres / positions de sortie. Par exemple, si votre méthode construit une nouvelle liste et la remplit de nouvelles données, quel mal cela fait-il de la renvoyer? Mais pensez également à l'évolution des API, voulez-vous vous limiter à toujours avoir à renvoyer une liste à l'avenir? Pas de discussions faciles, j'en ai peur.


Je pense que votre question est en fait un double et est abordée par ces réponses (en gros) - C'est un scénario d'utilisation. Un tel scénario utilise IDictionary ou dynamic types dynamic ( System.Dynamic.ExpandoObject ) pour cette question.


3 Réponses :


1
votes

Si vous regardez cela du point de vue des frais généraux, je pense que le meilleur pari est l'intermédiaire entre les deux, ISet<T> et sa mise en œuvre de HashSet<T> .

Les ensembles sont souvent négligés, mais sont extrêmement efficaces pour déterminer la «propriété» et économiser de l'espace en ne se fiant pas aux clés puisqu'ils ne se préoccupent pas de la commande.

EDIT (2020/11/18) - Il est important de noter que lors de l'ajout d'un élément au HashSet, son HashCode sera calculé. Le coût de cette opération peut être coûteux et annuler ainsi tous les avantages de performances que vous pourriez tirer de recherches plus rapides.

La différence importante est que Add() , Remove() et Contains() deviennent tous o (1) (vs le coût typiquement o (n) de IList<T> .

Il existe également SortedSet<T> si la commande devient un problème.

Voici un excellent article expliquant que c'est une bien meilleure profondeur que moi. Un extrait important:

Le HashSet<T> est l'ensemble de choix si vous voulez les recherches les plus rapides possibles mais ne vous souciez pas de l'ordre. En revanche, SortedSet<T> vous donnera une collection triée avec une légère réduction des performances.


4 commentaires

Certaines informations trompeuses ici - les hashsets, bien qu'excellents pour une recherche rapide, ne sont pas toujours meilleurs. Vous devez garder à l'esprit que l'ajout de quelque chose à un jeu de hachage nécessite le calcul du hachage de l'élément, ce qui, selon le cas d'utilisation particulier, peut annuler complètement les avantages de la recherche en termes de performances. Comprenez-le et utilisez-le à bon escient ...


Si vous lisez attentivement, je ne prétends pas que les HashSet sont une solution miracle. Je précise la valeur qu'ils peuvent apporter dans un cas d'utilisation particulier, en décrivant même les cas où il y a optimal.


En le relisant attentivement, je ne vois toujours aucun inconvénient implicite du HashSet <T>. Mais cela devrait être facile à remédier. Je serais heureux de voter une fois que vous l'aurez mis à jour pour donner une vue plus équilibrée. Les HashSets sont en effet souvent négligés et votre contribution sur ce point est la bienvenue!


@IgorPashchuk mis à jour pour inclure votre note sur les hashcodes



-1
votes

La réponse courte est que vous pouvez simplement utiliser IList pour n'importe quelle liste d'éléments. En fait, IList implémente ICollection et ICollection implémente IEnumerable. Vous êtes en mesure de décider du niveau d'abstraction dont vous avez besoin en fonction du contexte.

Voir ce lien pour plus de détails.


3 commentaires

eh bien ... je ne vais pas vous rejeter (étant donné votre représentant), mais la question ici reflète le titre: "Quel scénario serait-il ... préférable ... d'utiliser ICollection<T> sur IList<T> . Donc, cette réponse ne se rapporte pas vraiment à la question, ni à l'enquête.


De plus, vous devriez probablement utiliser des termes comme «implémente» ou même «dérive» au lieu de sous-interface pour se rapporter au matériel OOP auquel nous sommes plus habitués. De plus, il est douteux que vous deviez penser aux interfaces de manière hiérarchique. Je ne l'ai pas vraiment approfondi pour donner une certitude ici, mais il s'agit de savoir si vous êtes capable de déterminer, pendant l'exécution, s'il existe une interface dérivée de l'interface de base d'une instance d'un certain type; s'il est possible de le faire, je pourrais voir l'intérêt de penser en ces termes.


Merci @ brett-caswell pour votre commentaire. Mise à jour de la réponse en conséquence.



2
votes

La réponse est très subjective. Il s'agit davantage de ce dont vous avez besoin.

  • Si tout ce dont vous avez besoin est de parcourir tous les éléments, préférez IEnumerable<T>
  • Si vous avez besoin de manipuler la collection ( Add , Remove etc.) ICollection<T> doit être utilisé.
  • Si vous comptez utiliser fréquemment Index, utilisez IList<T> .
  • Si vous prévoyez de faire toutes sortes de manipulations, utilisez List<T> .

Cependant, dans ces cas, il existe IReadonlyCollcetion<T> et IReadonlyList<T> , cela rend la collection retournée immuable et devrait à nouveau venir après IEnumerable mais préférée par rapport à ICollection<T> et IList<T> .

Le but final est toujours d'utiliser des types aussi abstraits que possible. Ceci est basé sur les principes Code for the interfaces not for the implementation .

Edit: Pour cette question, je dirais que le besoin d'indexation est le principal facteur de préférence l'un par rapport à l'autre.


2 commentaires

Opinion controversée. Je demande IReadOnlyCollection lorsque je veux IReadOnlyCollection l'énumérable plus d'une fois. Je crée également des énumérables qui ne peuvent pas être itérés plus d'une fois.


Des énumérations multiples ainsi que des énumérations non ordonnées IReadOnlyColection seront vraiment meilleures. une réponse analogue serait, si c'est foreach toujours IEnumerable fonctionne, si une boucle for, alors IReadOnlyCollection . Mais encore une fois, même si for loop peut faire tout ce que foreach fait, nous utilisons foreach dans la mesure du possible.