Collection versus Liste que devez-vous utiliser sur vos interfaces?

Le code ressemble à celui-ci:

namespace Test { public interface IMyClass { List GetList(); } public class MyClass : IMyClass { public List GetList() { return new List(); } } } 

Lorsque j’parsing le code, j’obtiens la recommandation suivante.

Avertissement 3 CA1002: Microsoft.Design: modifiez ‘Liste’ dans ‘IMyClass.GetList ()’ pour utiliser Collection, ReadOnlyCollection ou KeyedCollection

Comment dois-je résoudre ce problème et quelle est la bonne pratique ici?

Pour répondre à la partie “pourquoi” de la question de savoir pourquoi pas List , les raisons sont la pérennité et la simplicité de l’API.

À l’épreuve du temps

List n’est pas conçu pour être facilement extensible en le sous-classant; il est conçu pour être rapide pour les implémentations internes. Vous remarquerez que les méthodes ne sont pas virtuelles et ne peuvent donc pas être remplacées, et il n’y a pas de hook dans ses opérations Add / Insert / Remove .

Cela signifie que si vous devez modifier le comportement de la collection à l’avenir (par exemple, pour rejeter les objects nuls que les gens essaient d’append ou pour effectuer des tâches supplémentaires, comme la mise à jour de l’état de la classe), vous devez changer le type. de collection, vous retournez à celle que vous pouvez sous-classer, ce qui sera un changement d’interface (bien sûr, changer la sémantique de choses comme ne pas autoriser null peut aussi être un changement d’interface, mais la mise à jour de

Ainsi, en retournant une classe facilement subdivisable telle que Collection ou une interface telle que IList , ICollection ou IEnumerable vous pouvez modifier votre implémentation interne pour qu’elle corresponde à un autre type de collection vos besoins, sans casser le code des consommateurs car il peut toujours être retourné comme le type qu’ils attendent.

Simplicité API

List contient de nombreuses opérations utiles telles que BinarySearch , Sort , etc. Cependant, s’il s’agit d’une collection que vous exposez, il est probable que vous contrôliez la sémantique de la liste, et non les consommateurs. Donc, même si votre classe en interne peut avoir besoin de ces opérations, il est très peu probable que les consommateurs de votre classe veuillent (ou même devraient) les appeler.

Ainsi, en offrant une interface ou une classe de collecte plus simple, vous réduisez le nombre de membres que les utilisateurs de votre API voient et simplifiez leur utilisation.

Je le déclarerais personnellement pour renvoyer une interface plutôt qu’une collection concrète. Si vous voulez vraiment accéder à la liste, utilisez IList . Sinon, considérez ICollection et IEnumerable .

Il s’agit surtout d’abstraire vos propres implémentations au lieu d’exposer directement l’object List à manipuler.

Ce n’est pas une bonne pratique de laisser d’autres objects (ou personnes) modifier directement l’état de vos objects. Pensez aux getters / setters de propriété.

Collection -> Pour collection normale
ReadOnlyCollection -> Pour les collections à ne pas modifier
KeyedCollection -> Lorsque vous voulez des dictionnaires à la place.

Comment résoudre ce problème dépend de ce que vous voulez que votre classe fasse et de la méthode GetList (). Peux-tu élaborer?

Dans ce genre de cas, j’essaie généralement d’exposer le minimum d’implémentation nécessaire. Si les consommateurs n’ont pas besoin de savoir que vous utilisez réellement une liste, vous n’avez pas besoin de retourner une liste. En revenant comme Microsoft suggère une collection, vous cachez le fait que vous utilisez une liste des consommateurs de votre classe et les isolez contre un changement interne.

Je ne pense pas que quelqu’un ait répondu à la partie “pourquoi” encore … alors voilà. La raison pour laquelle “vous” devriez “utiliser” une Collection au lieu d’une List est que si vous exposez une List , toute personne ayant access à votre object peut modifier les éléments de la liste. Alors que Collection est censé indiquer que vous créez vos propres méthodes “Ajouter”, “Supprimer”, etc.

Vous n’avez probablement pas besoin de vous en soucier, car vous codez probablement l’interface pour vous seul (ou peut-être quelques collègues). Voici un autre exemple qui pourrait avoir un sens.

Si vous avez un tableau public, ex:

 public int[] MyIntegers { get; } 

Vous penseriez que parce qu’il n’y a qu’un accesseur “get” que personne ne peut gâcher avec les valeurs, mais ce n’est pas vrai. Tout le monde peut changer les valeurs à l’intérieur, comme ceci:

 someObject.MyIngegers[3] = 12345; 

Personnellement, je voudrais juste utiliser List dans la plupart des cas. Mais si vous concevez une bibliothèque de classes que vous allez dissortingbuer à des développeurs aléatoires, et que vous devez vous fier à l’état des objects, vous devrez créer votre propre collection et la verrouiller à partir de là: )

Quelque chose à append, même si cela fait longtemps que cela n’a pas été demandé.

Lorsque votre type de liste dérive de List au lieu de Collection , vous ne pouvez pas implémenter les méthodes virtuelles protégées que Collection implémente. Cela signifie que votre type dérivé ne peut pas répondre si des modifications sont apscopes à la liste. En effet, List suppose que vous êtes au courant lorsque vous ajoutez ou supprimez des éléments. Etre capable de répondre aux notifications est une surcharge et donc List ne l’offre pas.

Dans les cas où le code externe a access à votre collection, vous ne pouvez pas contrôler le moment où un élément est ajouté ou supprimé. Par conséquent, Collection fournit un moyen de savoir quand votre liste a été modifiée.

Je ne vois aucun problème à retourner quelque chose comme

 this.InternalData.Filter(crteria).ToList(); 

Si j’ai renvoyé une copie déconnectée de données internes ou un résultat détaché d’une requête de données, je peux retourner en toute sécurité List sans exposer aucun détail d’implémentation et permettre d’utiliser les données renvoyées de manière pratique.

Mais cela dépend du type de consommateur auquel je m’attendais – si c’est quelque chose comme une grid de données, je préfère retourner IEnumerable qui sera dans la plupart des cas la liste copiée des éléments 🙂

La classe Collection est simplement une classe d’encapsulation autour d’autres collections pour masquer leurs détails d’implémentation et d’autres fonctionnalités. Je pense que cela a quelque chose à voir avec le modèle de codage masquant les propriétés dans les langages orientés object.

Je pense que vous ne devriez pas vous en soucier, mais si vous voulez vraiment faire plaisir à l’outil d’parsing de code, procédez comme suit:

 //using System.Collections.ObjectModel; Collection myCollection = new Collection(myList);