Je sais que IList est l'interface et List est le type concret mais je ne sais toujours pas quand utiliser chacun d'eux. Ce que je fais maintenant, c'est que si je n'ai pas besoin des méthodes Sort ou FindAll, j'utilise l'interface. Ai-je raison? Existe-t-il une meilleure façon de décider quand utiliser l'interface ou le type de béton?
180
Réponses:
Il y a deux règles que je suis:
Ainsi, lorsque vous écrivez une fonction ou une méthode qui prend une collection, écrivez-la non pas pour prendre un List, mais un IList <T>, un ICollection <T> ou IEnumerable <T>. Les interfaces génériques fonctionneront toujours même pour les listes hétérogènes car System.Object peut également être un T. Cela vous évitera des maux de tête si vous décidez d'utiliser une pile ou une autre structure de données plus tard. Si tout ce que vous avez à faire dans la fonction est de la parcourir, IEnumerable <T> est vraiment tout ce que vous devriez demander.
D'autre part, lorsque vous renvoyez un objet hors d'une fonction, vous souhaitez donner à l'utilisateur l'ensemble d'opérations le plus riche possible sans qu'il ait à effectuer un transfert. Donc, dans ce cas, s'il s'agit d'un List <T> en interne, renvoyez une copie en tant que List <T>.
la source
if...else
chaîne avec leis
mot - clé pour figurer un type beaucoup plus riche pour cela et finissent par le lancer et l'utiliser de toute façon. Vous n'êtes donc pas nécessairement assuré de cacher quoi que ce soit en utilisant une interface de base, au lieu de simplement l'obscurcir. Cependant, rendre la tâche plus difficile peut également amener l'auteur du code à réfléchir à deux fois à la façon dont il l'utilise.Add()
etRemove()
peuvent avoir des effets au-delà de la simple collection. Renvoyer une interface en lecture seule, commeIEnumerable
c'est souvent le cas pour les méthodes de récupération de données. Votre consommateur peut le projeter dans un type plus riche selon ses besoins.Les directives Microsoft vérifiées par FxCop découragent l'utilisation de List <T> dans les API publiques - préférez IList <T>.
Incidemment, je déclare maintenant presque toujours les tableaux unidimensionnels comme IList <T>, ce qui signifie que je peux systématiquement utiliser la propriété IList <T> .Count plutôt que Array.Length. Par exemple:
la source
Il y a une chose importante que les gens semblent toujours oublier:
Vous pouvez passer un tableau simple à quelque chose qui accepte un
IList<T>
paramètre, puis vous pouvez appelerIList.Add()
et recevoir une exception d'exécution:Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.
Par exemple, considérez le code suivant:
Si vous appelez cela comme suit, vous obtiendrez une exception d'exécution:
Cela se produit parce que l'utilisation de tableaux simples avec
IList<T>
viole le principe de substitution de Liskov.Pour cette raison, si vous appelez,
IList<T>.Add()
vous voudrez peut-être envisager d'exiger un fichier auList<T>
lieu d'unIList<T>
.la source
List<T>
plusIList<T>
, vous devriez aussi être conscient des raisons pour lesquellesIList<T>
est recommandé. (Par exemple, blogs.msdn.microsoft.com/kcwalina/2005/09/26/… )IList<T>.Add()
. Je ne dis pas que vous ne devriez pas utiliserIList<T>
- je signale simplement un piège possible. (J'ai tendance à utiliserIEnumerable<T>
ouIReadOnlyList<T>
ouIReadOnlyCollection<T>
de préférenceIList<T>
si je peux.)Je serais d'accord avec les conseils de Lee pour prendre des paramètres, mais ne pas revenir.
Si vous spécifiez vos méthodes pour renvoyer une interface, cela signifie que vous êtes libre de modifier l'implémentation exacte ultérieurement sans que la méthode consommatrice ne le sache jamais. Je pensais que je n'aurais jamais besoin de changer d'une liste <T> mais j'ai dû changer plus tard pour utiliser une bibliothèque de listes personnalisée pour les fonctionnalités supplémentaires qu'elle fournissait. Parce que je n'avais renvoyé qu'un IList <T>, aucune des personnes qui utilisaient la bibliothèque n'a dû changer son code.
Bien sûr, cela ne doit s'appliquer qu'aux méthodes visibles de l'extérieur (c'est-à-dire aux méthodes publiques). J'utilise personnellement des interfaces même dans le code interne, mais comme vous pouvez changer tout le code vous-même si vous apportez des modifications de rupture, ce n'est pas strictement nécessaire.
la source
IEnumerable
Vous devriez essayer d'utiliser le type le moins spécifique qui correspond à votre objectif.
IEnumerable
est moins spécifique queIList
.Vous utilisez
IEnumerable
lorsque vous souhaitez parcourir les éléments d'une collection.IList
IList
met en œuvreIEnumerable
.Vous devez l'utiliser
IList
lorsque vous avez besoin d'accéder par index à votre collection, ajouter et supprimer des éléments, etc ...Liste des
List
outilsIList
.la source
Il est toujours préférable d'utiliser le type de base le plus bas possible. Cela donne à l'implémenteur de votre interface, ou au consommateur de votre méthode, la possibilité d'utiliser ce qu'il veut dans les coulisses.
Pour les collections, vous devez viser à utiliser IEnumerable lorsque cela est possible. Cela donne le plus de flexibilité mais n'est pas toujours adapté.
la source
ToList()
retourner votre produitIEnumerable<T>
qui était déjà une liste et renvoyez-en un à laIList<T>
place. Désormais, les clients peuvent bénéficier de ce que vous pouvez offrir sans effort.Si vous travaillez dans une seule méthode (ou même dans une seule classe ou un seul assembly dans certains cas) et que personne à l'extérieur ne verra ce que vous faites, utilisez la plénitude d'une liste. Mais si vous interagissez avec du code extérieur, comme lorsque vous renvoyez une liste à partir d'une méthode, vous ne voulez que déclarer l'interface sans nécessairement vous attacher à une implémentation spécifique, surtout si vous n'avez aucun contrôle sur qui compile contre votre code après. Si vous avez commencé avec un type concret et que vous avez décidé de changer pour un autre, même s'il utilise la même interface, vous allez casser le code de quelqu'un d'autre à moins que vous n'ayez commencé avec une interface ou un type de base abstrait.
la source
Je ne pense pas qu'il y ait de règles strictes et rapides pour ce type de chose, mais j'utilise généralement la directive la plus légère possible jusqu'à ce que cela soit absolument nécessaire.
Par exemple, disons que vous avez une
Person
classe et uneGroup
classe. UneGroup
instance a de nombreuses personnes, donc une liste ici aurait du sens. Quand je déclare l'objet de liste dansGroup
j'utiliserai unIList<Person>
et l'instancierai en tant queList
.Et, si vous n'avez même pas besoin de tout,
IList
vous pouvez toujours l'utiliserIEnumerable
aussi. Avec les compilateurs et les processeurs modernes, je ne pense pas qu'il y ait vraiment de différence de vitesse, donc c'est plus juste une question de style.la source
Il est le plus souvent préférable d'utiliser le type utilisable le plus général, dans ce cas, IList ou mieux encore l'interface IEnumerable, afin de pouvoir changer l'implémentation plus facilement ultérieurement.
Cependant, dans .NET 2.0, il y a une chose ennuyeuse - IList n'a pas de méthode Sort () . Vous pouvez utiliser à la place un adaptateur fourni:
la source
Vous ne devez utiliser l'interface que si vous en avez besoin, par exemple, si votre liste est transtypée en une implémentation IList autre que List. Cela est vrai lorsque, par exemple, vous utilisez NHibernate, qui convertit les ILists dans un objet sac NHibernate lors de la récupération de données.
Si List est la seule implémentation que vous utiliserez pour une certaine collection, n'hésitez pas à la déclarer comme une implémentation concrète de List.
la source
Dans les situations que je rencontre habituellement, j'utilise rarement IList directement.
Habituellement, je l'utilise juste comme argument d'une méthode
Cela me permettra de faire un traitement générique sur presque tous les tableaux du framework .NET, à moins qu'il n'utilise IEnumerable et non IList, ce qui arrive parfois.
Cela dépend vraiment du type de fonctionnalité dont vous avez besoin. Je suggère d'utiliser la classe List dans la plupart des cas. IList est le meilleur lorsque vous avez besoin de créer un tableau personnalisé qui pourrait avoir des règles très spécifiques que vous souhaitez encapsuler dans une collection afin de ne pas vous répéter, mais que vous voulez quand même que .NET le reconnaisse comme une liste.
la source
L'objet AList vous permet de créer une liste, d'y ajouter des éléments, de la supprimer, de la mettre à jour, de l'indexer, etc. La liste est utilisée chaque fois que vous voulez juste une liste générique dans laquelle vous spécifiez le type d'objet et c'est tout.
IList, quant à lui, est une interface. Fondamentalement, si vous souhaitez créer votre propre type de liste, par exemple une classe de liste appelée BookList, vous pouvez utiliser l'interface pour vous donner les méthodes de base et la structure de votre nouvelle classe. IList est utilisé lorsque vous souhaitez créer votre propre sous-classe spéciale qui implémente List.
Une autre différence est: IList est une interface et ne peut pas être instancié. La liste est une classe et peut être instanciée. Ça veut dire:
la source