Question

Quel est le type de conteneur préféré lors du renvoi de plusieurs objets du même type à partir d'une fonction?

Est-il contraire aux bonnes pratiques de renvoyer un tableau simple (tel que MyType []), ou devriez-vous l'envelopper dans un conteneur générique (tel que ICollection < MyType >)?

Merci!

Était-ce utile?

La solution

Eric Lippert a un bon article à ce sujet. Au cas où vous ne voudriez pas lire l'article en entier, la réponse est: retournez l'interface.

Autres conseils

Renvoyez un IEnumerable<T> en utilisant un yield return .

Je renverrais un IList<T> car cela donne au consommateur de votre fonction la plus grande souplesse. Ainsi, si le consommateur de votre fonction n'a besoin que d'énumérer la séquence, il peut le faire, mais s'il souhaite utiliser la séquence sous forme de liste, il peut également le faire.

Mon principe général est d’accepter comme paramètre le type le moins restrictif et de renvoyer le type le plus riche possible. Ceci est, bien sûr, un acte d'équilibrage puisque vous ne voulez pas vous enfermer dans une interface ou une implémentation particulière (mais essayez toujours d'utiliser une interface).

Il s’agit de l’approche la moins présomptueuse que vous, développeur d’API, pouvez adopter. Ce n’est pas à vous de décider comment un consommateur de votre fonction utilisera ce qu’il vous envoie, c’est pourquoi vous renverriez un IEnumerable<T> dans ce cas, afin de lui donner la plus grande souplesse. Aussi, pour cette même raison, vous ne voudriez jamais savoir quel type de paramètre un consommateur vous enverra. Si vous devez seulement itérer une séquence qui vous est envoyée en tant que paramètre, définissez-le comme List<T> plutôt que <=>.

EDIT (monoxyde): Etant donné que la question ne devrait pas être close, je souhaite simplement ajouter un lien à partir de l'autre question à ce sujet: Pourquoi les tableaux sont-ils nocifs

Pourquoi pas List<T>?

De l'article d'Eric Lippert mentionné par d'autres, je pensais souligner ceci:

  

Si j'ai besoin d'une séquence, je l'utilise & # 8217;   IEnumerable<T> si j'ai besoin d'un mapping   des nombres contigus aux données I & # 8217; ll   utilisez un Dictionary<K,V>, si j'ai besoin d'un mapping   à travers des données arbitraires, je & # 8217; je vais utiliser un   HashSet<T>, si j'ai besoin d'un ensemble, je & # 8217; ll   utilisez un <=>. Je ne fais tout simplement pas & # 8217; pas besoin   des tableaux pour quoi que ce soit, donc je n'ai presque jamais   Utilise les. Ils ne & # 8217; ne résolvent pas un problème I   avoir mieux que les autres outils à mon   élimination.

Si la collection renvoyée est en lecture seule, ce qui signifie que vous ne souhaitez jamais que les éléments de la collection soient modifiés, utilisez IEnumerable<T>. C’est la représentation la plus élémentaire d’une séquence en lecture seule d’éléments immuables (du moins du point de vue de l’énumération elle-même).

Si vous souhaitez que ce soit une collection autonome pouvant être modifiée, utilisez ICollection<T> ou IList<T>.

Par exemple, si vous souhaitez renvoyer les résultats de la recherche d'un ensemble de fichiers particulier, renvoyez ensuite IEnumerable<FileInfo>.

.

Toutefois, si vous souhaitez exposer les fichiers d'un répertoire, vous devez également exposer IList/ICollection<FileInfo> car il est logique de vouloir éventuellement modifier le contenu de la collection.

Un bon conseil que j'ai souvent entendu cité est le suivant:

  

Soyez libéral dans ce que vous acceptez, précisez dans ce que vous fournissez.

En ce qui concerne la conception de votre API, je vous conseillerais de renvoyer une interface et non un type concret.

En prenant votre exemple de méthode, je le récrirais comme suit:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

La solution réside dans le fait que votre choix d'implémentation interne - utiliser une liste - n'est pas révélé à l'appelant, mais que vous retournez une interface appropriée.

Les propres directives de Microsoft sur le développement de framework recommandent de ne pas renvoyer de types spécifiques, favorisant les interfaces. (Désolé, je n'ai pas trouvé de lien pour cela)

De même, vos paramètres doivent être aussi généraux que possible. Au lieu d’accepter un tableau, acceptez un IEnumerable du type approprié. Ceci est compatible avec les tableaux ainsi que les listes et autres types utiles.

Reprenez votre exemple de méthode:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}
return ICollection<type>

L'avantage des types de retour génériques est que vous pouvez modifier l'implémentation sous-jacente sans changer le code qui l'utilise. L'avantage de renvoyer le type spécifique est que vous pouvez utiliser davantage de méthodes spécifiques au type.

Renvoyez toujours un type d'interface présentant le plus grand nombre de fonctionnalités pour l'appelant. Donc, dans votre cas, ICollection<YourType> devrait être utilisé.

Il est intéressant de noter que les développeurs de la BCL se sont en fait trompés à un endroit du framework .NET - voir cet article de blog d'Eric Lippert pour cette histoire.

Pourquoi pas IList<MyType>?

Il prend en charge l’indexation directe, caractéristique essentielle d’un tableau, sans supprimer la possibilité de renvoyer un List<MyType> un jour. Si vous souhaitez supprimer cette fonctionnalité, vous voudrez probablement retourner IEnumerable<MyType>.

Cela dépend de ce que vous envisagez de faire avec la collection que vous retournez. Si vous ne faites que répéter, ou si vous voulez que l'utilisateur répète, je suis d'accord avec @Daniel, retourne IEnumerable<T>. Toutefois, si vous souhaitez autoriser les opérations basées sur des listes, je renverrais IList<T>.

Utilisez des génériques. Il est plus facile d'interagir avec d'autres classes de collections et le système de types est plus en mesure de vous aider avec des erreurs potentielles.

L'ancien style de restitution d'un tableau était une béquille avant les génériques.

Ce qui rend votre code plus lisible, maintenable et plus facile pour VOUS. J'aurais utilisé le tableau simple, plus simple = mieux la plupart du temps. Bien que je dois vraiment voir le contexte pour donner la bonne réponse.

Il y a de gros avantages à préférer IEnumerable à toute autre solution, car cela vous donne la plus grande souplesse d'implémentation et vous permet d'utiliser des opérateurs yield return ou Linq pour une implémentation paresseuse.

Si l'appelant souhaite un List<T> choix, il peut simplement appeler ToList() ce que vous avez renvoyé. Les performances globales seront à peu près les mêmes que si vous aviez créé et renvoyé un nouveau <=> élément de votre méthode.

Un tableau est dangereux, mais ICollection<T> aussi.

ReadOnlyCollection<T> ne peut garantir que l'objet sera immuable.

Ma recommandation est d'encadrer l'objet renvoyé avec <=>

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top