Je ne sais pas quel type de collection je dois renvoyer à partir de mes méthodes et propriétés API publiques.
Les collections que j'ai en tête sont IList
, ICollection
et Collection
.
Le retour de l'un de ces types est-il toujours préféré aux autres ou dépend-il de la situation spécifique?
c#
.net
generics
collections
Rocky Singh
la source
la source
Réponses:
En règle générale, vous devez renvoyer un type le plus général possible, c'est-à-dire qui connaît juste assez les données renvoyées que le consommateur doit utiliser. De cette façon, vous avez une plus grande liberté pour modifier l'implémentation de l'API, sans casser le code qui l'utilise.
Considérez également l'
IEnumerable<T>
interface comme type de retour. Si le résultat doit être répété, le consommateur n'a pas besoin de plus que cela.la source
Count
méthode vérifie le type réel de la collection, elle utilisera donc les propriétésLength
ouCount
pour certains types connus comme les tableaux etICollection
même lorsque vous le fournissez en tant que fichierIEnumerable
.Thing<T>
implémenteIList<T>
mais pas le non génériqueICollection
, alors appelerIEnumerable<Cat>.Count()
aThing<Cat>
serait rapide, mais l'appelIEnumerable<Animal>.Count()
serait lent (puisque la méthode d'extension chercherait, et ne trouverait pas, une implémentation deICollection<Cat>
). Si la classe implémente le non-génériqueICollection
, cependant,IEnumerable<Animal>.Count
trouvera et l'utilisera.ICollection<T>
est une interface qui expose la sémantique de collecte , tels queAdd()
,Remove()
, etCount
.Collection<T>
est une implémentation concrète de l'ICollection<T>
interface.IList<T>
est essentiellement unICollection<T>
accès basé sur un ordre aléatoire.Dans ce cas, vous devez décider si vos résultats nécessitent ou non une sémantique de liste telle que l'indexation basée sur l'ordre (puis utilisez
IList<T>
) ou si vous devez simplement renvoyer un "sac" de résultats non ordonné (puis utiliserICollection<T>
).la source
Collection<T>
outilsIList<T>
et pas seulementICollection<T>
.IEnumerable<T>
ordonnées. Ce qui distingueIList<T>
deICollection<T>
est qu'il offre à ses membres de travailler avec des index. Par exemplelist[5]
fonctionne, maiscollection[5]
ne compile pas.IList<T>
. Il existe de nombreuses collections ordonnées qui ne le font pas.IList<T>
concerne l'accès indexé rapide.IEnumerable<T>
commandées? PrenezHashSet<T>
- il met en œuvreIEnumerable<T>
mais n'est clairement pas commandé. C'est-à-dire que vous n'avez aucune influence sur l'ordre des éléments et que cet ordre peut changer à tout moment, si la table de hachage interne est réorganisée.La principale différence entre
IList<T>
etICollection<T>
est queIList<T>
vous permet d'accéder aux éléments via un index.IList<T>
décrit les types de type tableau. Les éléments d'unICollection<T>
ne sont accessibles que par énumération. Les deux permettent l'insertion et la suppression d'éléments.Si vous avez seulement besoin d'énumérer une collection,
IEnumerable<T>
c'est préférable. Il présente deux avantages par rapport aux autres:Il interdit les modifications de la collection (mais pas des éléments, s'ils sont de type référence).
Il permet la plus grande variété de sources possible, y compris des énumérations générées par algorithme et qui ne sont pas du tout des collections.
Collection<T>
est une classe de base qui est principalement utile aux implémenteurs de collections. Si vous l'exposez dans des interfaces (API), de nombreuses collections utiles qui n'en dérivent pas seront exclues.Un inconvénient de
IList<T>
est que les tableaux l'implémentent mais ne vous permettent pas d'ajouter ou de supprimer des éléments (c'est-à-dire que vous ne pouvez pas modifier la longueur du tableau). Une exception sera levée si vous appelezIList<T>.Add(item)
un tableau. La situation est quelque peu désamorcée, tout commeIList<T>
une propriété booléenneIsReadOnly
que vous pouvez vérifier avant d'essayer de le faire. Mais à mes yeux, c'est encore un défaut de conception dans la bibliothèque . Par conséquent, j'utiliseList<T>
directement, lorsque la possibilité d'ajouter ou de supprimer des éléments est requise.la source
Collection
,ReadOnlyCollection
ouKeyedCollection
. Et celaList
ne devrait pas être retourné.IList<T>
, il n'y a aucun moyen de garantir que la méthode ne sera pas appelée avec un tableau comme paramètre.IList<T>
est l'interface de base de toutes les listes génériques. Puisqu'il s'agit d'une collection ordonnée, l'implémentation peut décider de l'ordre, allant de l'ordre trié à l'ordre d'insertion. De plus, laIlist
propriété Item permet aux méthodes de lire et de modifier les entrées de la liste en fonction de leur index. Cela permet d'insérer, de supprimer une valeur dans / de la liste à un index de position.Depuis
IList<T> : ICollection<T>
, toutes les méthodes deICollection<T>
sont également disponibles ici pour l'implémentation.ICollection<T>
est l'interface de base de toutes les collections génériques. Il définit la taille, les énumérateurs et les méthodes de synchronisation. Vous pouvez ajouter ou supprimer un élément dans une collection, mais vous ne pouvez pas choisir à quelle position il se trouve en raison de l'absence de propriété d'index.Collection<T>
fournit une implémentation pourIList<T>
,IList
etIReadOnlyList<T>
.Si vous utilisez un type d'interface plus étroit tel que
ICollection<T>
au lieu deIList<T>
, vous protégez votre code contre les modifications importantes. Si vous utilisez un type d'interface plus large tel queIList<T>
, vous risquez davantage d'interrompre les modifications de code.Citant d'un source ,
la source
Le retour d'un type d'interface est plus général, donc (faute d'informations supplémentaires sur votre cas d'utilisation spécifique), je pencherais vers cela. Si vous souhaitez exposer la prise en charge de l'indexation, choisissez
IList<T>
, sinonICollection<T>
cela suffira. Enfin, si vous souhaitez indiquer que les types renvoyés sont en lecture seule, choisissezIEnumerable<T>
.Et, au cas où vous ne l'auriez pas encore lu, Brad Abrams et Krzysztof Cwalina ont écrit un excellent livre intitulé "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" (vous pouvez télécharger un résumé à partir d' ici ).
la source
IEnumerable<T>
est en lecture seule? Bien sûr, mais lorsque vous le réaccordez dans un contexte de référentiel, même après avoir exécuté ToList, ce n'est pas thread-safe. Le problème est que lorsque la source de données d'origine obtient GC, IEnumarble.ToList () ne fonctionne pas dans un contexte multi-thread. Cela fonctionne sur un linéaire parce que GC est appelé après que vous ayez fait le travail, mais utiliserasync
maintenant un jour dans 4.5+ IEnumarbale devient un mal de balle.Il y a quelques sujets qui découlent de cette question:
Vous voudrez peut-être souligner que c'est une API orientée objet
interfaces contre classes
Si vous n'avez pas beaucoup d'expérience avec les interfaces, je vous recommande de vous en tenir aux classes. Je vois souvent des développeurs sauter aux interfaces, même si ce n'est pas nécessaire.
Et, finissez par faire une mauvaise conception d'interface, au lieu d'une bonne conception de classe, qui, d'ailleurs, peut éventuellement être migrée vers une bonne conception d'interface ...
Vous verrez beaucoup d'interfaces dans l'API, mais ne vous précipitez pas, si vous n'en avez pas besoin.
Vous apprendrez éventuellement à appliquer des interfaces à votre code.
quelle classe spécifique, parmi plusieurs classes identiques, collection, liste, tableau?
Il existe plusieurs classes en c # (dotnet) qui peuvent être interchangées. Comme déjà mentionné, si vous avez besoin de quelque chose d'une classe plus spécifique, telle que "CanBeSortedClass", rendez-le explicite dans votre API.
Votre utilisateur d'API a-t-il vraiment besoin de savoir que votre classe peut être triée ou d'appliquer un format aux éléments? Ensuite, utilisez "CanBeSortedClass" ou "ElementsCanBePaintedClass", sinon utilisez "GenericBrandClass".
Sinon, utilisez une classe plus générale.
Classes de collection communes et collections de sous-éléments ("génériques")
Vous constaterez qu'il existe des classes qui contiennent d'autres éléments, et vous pouvez spécifier que tous les éléments doivent être d'un type spécifique.
Les collections génériques sont ces classes que vous pouvez utiliser la même collection, pour plusieurs applications de code, sans avoir à créer une nouvelle collection, pour chaque nouveau type de sous-élément, comme ceci: Collection .
L'utilisateur de votre API va-t-il avoir besoin d'un type très spécifique, identique pour tous les éléments?
Utilisez quelque chose comme
List<WashingtonApple>
.Votre utilisateur d'API aura-t-il besoin de plusieurs types connexes?
Exposer
List<Fruit>
pour votre API, et utiliserList<Orange>
List<Banana>
, enList<Strawberry>
interne, oùOrange
,Banana
etStrawberry
sont les descendants deFruit
.Votre utilisateur d'API aura-t-il besoin d'une collection de types génériques?
Utilisez
List
, où se trouvent tous les élémentsobject
.À votre santé.
la source