Quand utiliser IList et quand utiliser la liste

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 si je n’ai pas besoin des méthodes Sort ou FindAll, j’utilise l’interface. Ai-je raison? Existe-t-il un meilleur moyen de décider quand utiliser l’interface ou le type de béton?

Il y a deux règles que je suis:

  • Acceptez le type le plus basique qui fonctionnera
  • Renvoyez le type le plus riche dont votre utilisateur aura besoin

Ainsi, lors de l’écriture d’une fonction ou d’une méthode prenant une collection, écrivez-la pour ne pas prendre de liste, mais un IList , un ICollection ou un IEnumerable . Les interfaces génériques continueront de fonctionner 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 stack ou une autre structure de données plus tard. Si tout ce que vous devez faire dans la fonction est à travers elle, IEnumerable est vraiment tout ce que vous devriez demander.

D’un autre côté, lorsque vous retournez un object hors d’une fonction, vous voulez donner à l’utilisateur le jeu d’opérations le plus riche possible sans qu’il soit nécessaire de le lancer. Donc, dans ce cas, si c’est une liste en interne, retournez une copie sous forme de liste .

Les directives Microsoft vérifiées par FxCop découragent l’utilisation de List dans les API publiques – préférez IList .

Incidemment, je déclare presque toujours les tableaux à une dimension comme IList , ce qui signifie que je peux utiliser la propriété IList .Count plutôt que Array.Length. Par exemple:

 public interface IMyApi { IList GetReadOnlyValues(); } public class MyApiImplementation : IMyApi { public IList GetReadOnlyValues() { List myList = new List(); ... populate list return myList.AsReadOnly(); } } public class MyMockApiImplementationForUnitTests : IMyApi { public IList GetReadOnlyValues() { IList testValues = new int[] { 1, 2, 3 }; return testValues; } } 

Il y a une chose importante que les gens semblent toujours ignorer:

Vous pouvez passer un tableau brut à quelque chose qui accepte un paramètre IList , puis vous pouvez appeler IList.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:

 private void test(IList list) { list.Add(1); } 

Si vous appelez cela comme suit, vous obtiendrez une exception d’exécution:

 int[] array = new int[0]; test(array); 

Cela se produit car l’utilisation de tableaux simples avec IList viole le principe de substitution de Liskov.

Pour cette raison, si vous appelez IList.Add() vous pouvez envisager de demander une List au lieu d’un IList .

Je suis d’accord avec le conseil de Lee pour prendre des parameters, mais ne pas revenir.

Si vous spécifiez vos méthodes pour renvoyer une interface, cela signifie que vous êtes libre de modifier ultérieurement l’implémentation exacte sans que la méthode de consommation soit connue. Je pensais que je n’aurais jamais besoin de changer à partir d’une liste mais j’ai dû changer plus tard pour utiliser une bibliothèque de listes personnalisées pour les fonctionnalités supplémentaires fournies. Comme je n’avais renvoyé qu’un IList , aucune des personnes ayant utilisé la bibliothèque n’avait à changer de code.

Bien entendu, cela ne concerne que les méthodes visibles de l’extérieur (méthodes publiques). Personnellement, j’utilise des interfaces même dans le code interne, mais comme vous êtes capable de modifier tout le code vous-même si vous apportez des modifications, cela n’est pas ssortingctement nécessaire.

IEnumerable vous devriez essayer d’utiliser le type le moins spécifique qui convient à votre objective. IEnumerable est moins spécifique que IList Vous utilisez IEnumerable lorsque vous souhaitez parcourir les éléments d’une collection

IList IList implémente IEnumerable Vous devez utiliser IList lorsque vous devez accéder par index à votre collection, append et supprimer des éléments, etc.

List List implémente IList

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’ils veulent dans les coulisses.

Pour les collections, vous devriez essayer d’utiliser IEnumerable dans la mesure du possible. Cela donne le plus de flexibilité mais n’est pas toujours adapté.

Si vous travaillez dans une méthode unique (ou même dans une classe ou un assemblage unique dans certains cas) et que personne à l’extérieur ne va voir ce que vous faites, utilisez la plénitude d’une liste. Mais si vous interagissez avec du code externe, comme lorsque vous retournez une liste à partir d’une méthode, vous ne souhaitez déclarer l’interface que si vous n’avez pas nécessairement besoin d’une implémentation spécifique, surtout si vous ne contrôlez pas qui comstack code après. Si vous avez commencé avec un type concret et que vous avez décidé d’en changer un, même s’il utilise la même interface, vous allez casser le code de quelqu’un sauf si vous avez démarré avec une interface ou un type de base abstrait.

Je ne pense pas qu’il existe des règles ssortingctes pour ce type de chose, mais j’utilise généralement la méthode la plus légère jusqu’à ce que ce soit absolument nécessaire.

Par exemple, supposons que vous ayez une classe Person et une classe Group . Une instance de Group a beaucoup de personnes, donc une liste ici aurait du sens. Lorsque je déclare l’object de liste dans le Group I, je vais utiliser un IList et l’instancier en tant que List .

 public class Group { private IList people; public Group() { this.people = new List(); } } 

Et si vous n’avez même pas besoin de tout dans IList vous pouvez toujours utiliser IEnumerable . Avec les compilateurs et processeurs modernes, je ne pense pas qu’il y ait vraiment de différence de vitesse, donc c’est plus une question de style.

Il est souvent préférable d’utiliser le type utilisable le plus général, en l’occurrence l’IList ou mieux encore l’interface IEnumerable, pour pouvoir changer d’implémentation ultérieurement.

Cependant, dans .NET 2.0, il y a une chose ennuyeuse: IList n’a pas de méthode Sort () . Vous pouvez utiliser un adaptateur fourni à la place:

 ArrayList.Adapter(list).Sort() 

L’object AList vous permet de créer une liste, d’y append des éléments, de la supprimer, de la mettre à jour, de l’indexer, etc. La liste est utilisée lorsque vous souhaitez simplement une liste générique dans laquelle vous spécifiez le type d’object.

IList d’autre part est une interface. Fondamentalement, si vous voulez créer votre propre type de liste, par exemple une classe de liste appelée BookList, vous pouvez utiliser l’interface pour vous donner des méthodes et une structure de base pour votre nouvelle classe. IList est utilisé lorsque vous voulez créer votre propre sous-classe spéciale qui implémente List.

Une autre différence est que: IList est une interface et ne peut pas être instancié. List est une classe et peut être instanciée. Ça veut dire:

 IList MyList = new IList(); List MyList = new List 

Dans les situations que je rencontre habituellement, j’utilise rarement IList directement.

D’habitude je l’utilise juste comme argument pour une méthode

 void ProcessArrayData(IList almostAnyTypeOfArray) { // Do some stuff with the IList array } 

Cela me permettra de faire du traitement générique sur presque toutes les masortingces du framework .NET, à moins qu’il 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 mieux adapté lorsque vous devez créer un tableau personnalisé pouvant contenir des règles très spécifiques que vous souhaitez encapsuler dans une collection afin de ne pas vous répéter, tout en souhaitant que .NET le reconnaisse comme une liste.

Vous devez utiliser l’interface uniquement si vous en avez besoin, par exemple si votre liste est convertie en une implémentation IList autre que List. Cela est vrai lorsque, par exemple, vous utilisez NHibernate, qui convertit ILists en object bag NHibernate lors de la récupération des données.

Si List est la seule implémentation que vous utiliserez jamais pour une collection donnée, n’hésitez pas à la déclarer comme une implémentation de liste concrète.