Dois-je toujours retourner IEnumerable au lieu de IList ?

Lorsque j’écris mon code DAL ou un autre code qui renvoie un ensemble d’éléments, dois-je toujours faire ma déclaration de retour:

public IEnumerable GetRecentItems() 

ou

 public IList 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 semblait correct car je retournais le type de données le plus générique tout en décrivant ce qu’il faisait, mais peut-être que ce n’est pas correct.

Cela dépend vraiment de la raison pour laquelle vous utilisez cette interface spécifique.

Par exemple, IList a plusieurs méthodes qui ne sont pas présentes dans IEnumerable :

  • 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 façon que ce soit, alors retournez IList .

De plus, si la méthode qui utilise votre résultat IEnumerable attend un IList , cela évitera au CLR de prendre en compte les conversions requirejses, optimisant ainsi le code compilé.

Les instructions de conception de structure 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érable à un simple IList est que IList n’informe pas l’appelant en lecture seule ou non.

Si vous retournez un IEnumerable place, certaines opérations peuvent être un peu plus délicates pour l’appelant. De plus, vous ne laisserez plus à l’appelant la possibilité de modifier la collection, ce que vous pouvez souhaiter ou ne pas vouloir.

N’oubliez pas que LINQ contient quelques astuces et optimisera certains appels en fonction du type sur lequel ils sont effectués. Ainsi, par exemple, si vous effectuez un compte et que la collection sous-jacente est une liste, elle ne parcourra PAS tous les éléments.

Personnellement, pour un ORM, je restrais probablement avec Collection comme valeur de retour.

Ça dépend…

Le retour du type le moins dérivé ( IEnumerable ) vous laissera le plus de latitude pour modifier l’implémentation sous-jacente.

Le retour 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é qui a toutes les opérations dont vos utilisateurs auront besoin … donc, en gros, 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.

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 grand nombre de consommateurs.

Soyez libre dans ce que vous exigez et explicite dans ce que vous fournissez.

List offre au code d’appel de nombreuses autres fonctionnalités, telles que la modification de l’object renvoyé et l’access par index. Donc, la question se résume à: dans le cas d’utilisation spécifique de votre application, souhaitez-vous prendre en charge de telles utilisations (probablement en retournant une collection fraîchement construite!), Pour la commodité de l’appelant? l’appelant a besoin de parcourir la collection et de renvoyer en toute sécurité une référence à une collection sous-jacente réelle sans craindre que cela ne soit modifié par erreur, etc.

Seulement vous pouvez répondre à cette question, et seulement en comprenant bien ce que vos interlocuteurs voudront faire avec la valeur de retour, et quelle est l’importance des performances (quelle taille ont les collections que vous copiez, quelle est la probabilité que cela gêne, etc).

Une chose à prendre en compte est que si vous utilisez une instruction LINQ à exécution différée pour générer votre IEnumerable , 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 parcourt, 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 appel simple méthode facile – je n’ai pas besoin de prendre cette décision pour eux, ce qui rend mon code légèrement plus efficace dans les cas où l’appelant ne fait que faire une foreach.

Je pense que vous pouvez utiliser non plus, mais chacun a un usage. Fondamentalement, la List est IEnumerable mais vous avez la fonctionnalité de comptage, append un élément, supprimer un élément

IEnumerable n’est pas efficace pour compter des éléments

Si la collection est destinée à être en lecture seule ou si la modification de la collection est contrôlée par le Parent il n’est pas judicieux de renvoyer une liste IList uniquement pour Count .

Dans Linq, il y a une méthode d’extension Count() sur IEnumerable qui, à l’intérieur du CLR, raccourcira vers .Count si le type sous-jacent est de type IList , la différence de performance est donc négligeable.

En général, je pense (opinion) qu’il est préférable de renvoyer IEnumerable autant que possible, si vous devez faire des ajouts, puis append ces méthodes à la classe parente, sinon le consommateur gère alors la collection qui viole les principes, par exemple manufacturer.Models.Add(model) viole la loi de demeter. Bien sûr, ce ne sont que des lignes direcsortingces et non des règles ssortingctes, mais tant qu’il n’ya pas d’applications complètes, mieux vaut suivre aveuglément que de ne pas suivre du tout.

 public interface IManufacturer { IEnumerable Models {get;} void AddModel(Model model); } 

(Remarque: Si vous utilisez nNHibernate, vous devrez peut-être mapper sur IList privé en utilisant différents accesseurs.)

Ce n’est pas si simple quand vous parlez de valeurs de retour plutôt que de parameters 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 devez pouvoir parcourir la collection, vous prenez un IEnumberable alors que si vous devez append ou supprimer, vous prenez un IList.

Dans le cas d’une valeur de retour, c’est plus difficile. Qu’est-ce que votre interlocuteur attend? Si vous retournez un IEnumerable, alors il ne saura pas a priori qu’il peut en faire un IList. Mais si vous retournez un IList, il saura qu’il peut le parcourir. Donc, vous devez tenir compte de ce que votre appel va faire avec les données. Les fonctionnalités dont votre interlocuteur a besoin / attend sont celles qui devraient régir la décision de retour.

Comme tout le monde a dit que cela dépend, si vous ne voulez pas append / supprimer la fonctionnalité à la couche appelante, alors je voterai pour IEnumerable, car il ne fournit que des fonctionnalités de base qui, dans la conception, me plaisent. En revenant à IList, mes votes sont toujours présents mais c’est surtout ce que vous aimez et ce que vous n’aimez pas. en termes de performance, je pense qu’ils sont plus semblables.

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 de code externe), par exemple, pour une logique d’ iterator de rendement et des ressources de mémoire ).

Cependant, si vous avez besoin d’éléments, n’oubliez pas qu’il existe une autre couche entre IEnumerable et IList- ICollection .

Je suis peut-être un peu absent, vu que personne d’autre ne l’a suggéré jusqu’à présent, mais pourquoi ne renvoyez-vous pas une collection (I)Collection ?

D’après ce dont je me souviens, Collection était le type de retour préféré sur List car il supprime l’implémentation. Ils implémentent tous IEnumerable , mais cela me semble un peu trop bas pour le travail.

Je pense que vous pouvez utiliser non plus, mais chacun a un usage. Fondamentalement, List est IEnumerable mais vous avez la fonctionnalité count, Add element, remove element

IEnumerable n’est pas efficace pour compter des éléments ou pour obtenir un élément spécifique dans la collection.

List est une collection idéale pour trouver des éléments spécifiques, append facilement des éléments ou les supprimer.

En général, j’essaie d’utiliser List dans la mesure du possible car cela me donne plus de flexibilité.

Utilisez List getRecentItems() plutôt que IList GetRecentItems()

Je pense que la règle générale est d’utiliser la classe la plus spécifique pour retourner, pour éviter de faire un travail inutile et donner plus d’options à votre interlocuteur.

Cela dit, je pense qu’il est plus important de considérer le code que vous écrivez que le code que le prochain utilisateur va écrire (dans des limites raisonnables). C’est parce que vous pouvez faire des suppositions sur le code qui existe déjà.

Rappelez-vous que le passage à une collection de IEnumerable dans une interface fonctionnera, le passage à IEnumerable à partir d’une collection rompra le code existant.

Si toutes ces opinions semblent contradictoires, c’est parce que la décision est subjective.