Lorsque j'écris mon DAL ou un autre code qui renvoie un ensemble d'articles, dois-je toujours faire ma déclaration de retour:
public IEnumerable<FooBar> GetRecentItems()
ou
public IList<FooBar> GetRecentItems()
Actuellement, dans mon code, j'ai essayé d'utiliser IEnumerable autant que possible, mais je ne suis pas sûr que ce soit la meilleure pratique? Cela me semblait juste parce que je renvoyais le type de données le plus générique tout en étant toujours descriptif de ce qu'il fait, mais peut-être que ce n'est pas correct à faire.
c#
ienumerable
KingNestor
la source
la source
Réponses:
Cela dépend vraiment de la raison pour laquelle vous utilisez cette interface spécifique.
Par exemple,
IList<T>
a plusieurs méthodes qui ne sont pas présentes dansIEnumerable<T>
:IndexOf(T item)
Insert(int index, T item)
RemoveAt(int index)
et propriétés:
T this[int index] { get; set; }
Si vous avez besoin de ces méthodes de quelque manière que ce soit, revenez certainement
IList<T>
.De plus, si la méthode qui consomme votreIEnumerable<T>
résultat attend unIList<T>
, cela évitera au CLR de prendre en compte les conversions requises, optimisant ainsi le code compilé.la source
Les directives de conception de l'infrastructure recommandent d'utiliser la classe Collection lorsque vous devez renvoyer une collection modifiable par l'appelant ou ReadOnlyCollection pour les collections en lecture seule.
La raison pour laquelle cela est préféré à un simple
IList
est queIList
cela n'informe pas l'appelant s'il est en lecture seule ou non.Si vous renvoyez un à la
IEnumerable<T>
place, certaines opérations peuvent être un peu plus délicates à effectuer pour l'appelant. De plus, vous ne donnerez plus à l'appelant la possibilité de modifier la collection, ce que vous voudrez peut-être ou non.Gardez à l'esprit que LINQ contient quelques astuces dans sa manche et optimisera certains appels en fonction du type sur lequel ils sont exécutés. Ainsi, par exemple, si vous effectuez une
Count
et que la collection sous-jacente est une liste, elle ne parcourra PAS tous les éléments.Personnellement, pour un ORM, je m'en tiendrai probablement à
Collection<T>
ma valeur de retour.la source
En général, vous devez exiger le plus générique et renvoyer la chose la plus spécifique possible. Donc, si vous avez une méthode qui prend un paramètre et que vous n'avez vraiment besoin que de ce qui est disponible dans IEnumerable, cela devrait être votre type de paramètre. Si votre méthode peut renvoyer un IList ou un IEnumerable, préférez renvoyer IList. Cela garantit qu'il est utilisable par le plus large éventail de consommateurs.
Soyez lâche dans ce dont vous avez besoin et explicite dans ce que vous fournissez.
la source
Ça dépend...
Renvoyer le type le moins dérivé (
IEnumerable
) vous laissera la plus grande marge de manœuvre pour modifier l'implémentation sous-jacente sur la piste.Le renvoi d'un type plus dérivé (
IList
) fournit aux utilisateurs de votre API plus d'opérations sur le résultat.Je suggérerais toujours de renvoyer le type le moins dérivé contenant toutes les opérations dont vos utilisateurs auront besoin ... Donc, fondamentalement, vous devez d'abord déterminer quelles opérations sur le résultat ont du sens dans le contexte de l'API que vous définissez.
la source
Une chose à considérer est que si vous utilisez une instruction LINQ à exécution différée pour générer votre
IEnumerable<T>
, appeler.ToList()
avant de revenir de votre méthode signifie que vos éléments peuvent être itérés deux fois - une fois pour créer la liste, et une fois lorsque l'appelant fait une boucle. , filtre ou transforme votre valeur de retour. Lorsque cela est possible, j'aime éviter de convertir les résultats de LINQ-to-Objects en une liste ou un dictionnaire concret jusqu'à ce que j'aie à le faire. Si mon appelant a besoin d'une liste, c'est un simple appel de méthode facile - je n'ai pas besoin de prendre cette décision pour lui, et cela rend mon code légèrement plus efficace dans les cas où l'appelant fait juste un foreach.la source
List<T>
offre au code appelant de nombreuses autres fonctionnalités, telles que la modification de l'objet retourné et l'accès par index. La question se résume donc à: dans le cas d'utilisation spécifique de votre application, VOULEZ-VOUS prendre en charge de telles utilisations (vraisemblablement en renvoyant une collection fraîchement construite!), Pour la commodité de l'appelant - ou voulez-vous de la vitesse pour le cas simple lorsque tout le l'appelant a besoin de parcourir la collection et vous pouvez en toute sécurité retourner une référence à une collection sous-jacente réelle sans craindre que cela ne la modifie par erreur, etc.?Vous seul pouvez répondre à cette question, et seulement en comprenant bien ce que vos appelants voudront faire avec la valeur de retour, et à quel point les performances sont importantes ici (quelle est la taille des collections que vous copieriez, quelle est la probabilité que cela soit un goulot d'étranglement, etc).
la source
Si la collection est destinée à être en lecture seule, ou si la modification de la collection est contrôlée par le,
Parent
renvoyer unIList
juste pourCount
n'est pas une bonne idée.Dans Linq, il existe une
Count()
méthode d'extension surIEnumerable<T>
laquelle à l'intérieur du CLR un raccourci vers.Count
si le type sous-jacent est deIList
, donc la différence de performances est négligeable.En général, je pense (opinion) qu'il est préférable de renvoyer IEnumerable lorsque cela est possible, si vous avez besoin de faire des ajouts, ajoutez ces méthodes à la classe parente, sinon le consommateur gère alors la collection dans Model qui viole les principes, par exemple
manufacturer.Models.Add(model)
viole la loi de demeter. Bien sûr, ce ne sont que des directives et non des règles strictes et rapides, mais jusqu'à ce que vous ayez une pleine compréhension de l'applicabilité, suivre aveuglément est mieux que de ne pas suivre du tout.(Remarque: si vous utilisez nNHibernate, vous devrez peut-être mapper vers IList privé en utilisant différents accesseurs.)
la source
Ce n'est pas si simple lorsque vous parlez de valeurs de retour au lieu de paramètres d'entrée. Lorsqu'il s'agit d'un paramètre d'entrée, vous savez exactement ce que vous devez faire. Donc, si vous avez besoin de pouvoir parcourir la collection, vous prenez un IEnumberable alors que si vous devez ajouter ou supprimer, vous prenez un IList.
Dans le cas d'une valeur de retour, c'est plus difficile. Qu'attend votre interlocuteur? Si vous retournez un IEnumerable, alors il ne saura pas a priori qu'il peut en faire un IList. Mais, si vous renvoyez un IList, il saura qu'il peut le parcourir. Donc, vous devez prendre en compte ce que votre appelant va faire avec les données. La fonctionnalité dont votre appelant a besoin / attend est ce qui devrait régir lors de la décision de retour.
la source
comme tous l'ont dit, cela dépend, si vous ne voulez pas ajouter / supprimer de fonctionnalité lors de l'appel de la couche, je voterai pour IEnumerable car il ne fournit que des itérations et des fonctionnalités de base qui, en perspective de conception, me plaisent. Retournant IList mes votes sont toujours à nouveau mais c'est principalement ce que vous aimez et ce qui ne l'est pas. en termes de performances, je pense qu'ils sont plus identiques.
la source
Si vous ne comptez pas dans votre code externe, il est toujours préférable de renvoyer IEnumerable, car plus tard, vous pouvez modifier votre implémentation (sans impact sur le code externe), par exemple, pour générer une logique d' itérateur et conserver les ressources mémoire (très bonne fonctionnalité de langage d'ailleurs ).
Cependant, si vous avez besoin d'un nombre d'éléments, n'oubliez pas qu'il existe une autre couche entre IEnumerable et IList - ICollection .
la source
Je suis peut-être un peu en retrait, voyant que personne d'autre ne l'a suggéré jusqu'à présent, mais pourquoi ne pas retourner un
(I)Collection<T>
?D'après ce dont je me souviens,
Collection<T>
le type de retour était préféréList<T>
car il fait abstraction de l'implémentation. Ils mettent tous en œuvreIEnumerable
, mais cela me semble un peu trop bas pour le travail.la source
Je pense que vous pouvez utiliser l'un ou l'autre, mais chacun a une utilité. Au fond
List
est ,IEnumerable
mais vous devez compter la fonctionnalité, l' élément Ajouter, supprimer élémentIEnumerable
n'est pas efficace pour compter les éléments ou obtenir un élément spécifique dans la collection.List
est une collection parfaitement adaptée à la recherche d'éléments spécifiques, facile à ajouter ou à supprimer.En général, j'essaye d'utiliser
List
là où c'est possible car cela me donne plus de flexibilité.Utilisez
List<FooBar> getRecentItems()
plutôt queIList<FooBar> GetRecentItems()
la source
Je pense que la règle générale est d'utiliser la classe la plus spécifique pour revenir, pour éviter de faire un travail inutile et donner plus d'options à votre appelant.
Cela dit, je pense qu'il est plus important de considérer le code que vous écrivez devant vous que le code que le prochain écrira (dans des limites raisonnables). C'est parce que vous pouvez faire des hypothèses sur le code qui existe déjà.
N'oubliez pas que déplacer UP vers une collection de IEnumerable dans une interface fonctionnera, descendre vers IEnumerable à partir d'une collection cassera le code existant.
Si ces opinions semblent toutes contradictoires, c'est que la décision est subjective.
la source
TL; DR; - résumé
List
) pour les valeurs de retour et le type le plus générique pour les paramètres d'entrée, même en cas de collections.IReadOnlyList
ouIReadOnlyCollection
comme type de valeur de retour.Plus
la source