Avez-vous ToList()?
Avez-vous un type par défaut que vous souhaitez utiliser dans vos relations avec les résultats de requêtes LINQ?
Par défaut LINQ sera de retour une IEnumerable<>
ou peut-être un IOrderedEnumerable<>
. Nous avons constaté qu'une List<>
est généralement plus utile pour nous, ont donc pris l'habitude de ToList()
ing nos requêtes, la plupart du temps, et certainement à l'aide de List<>
en fonction des arguments et valeurs de retour.
La seule exception à cette règle a été dans LINQ to SQL où l'appelant .ToList()
énumérerait les IEnumerable
prématurément.
Nous sommes également en utilisant WCF largement, la valeur par défaut type de collection qui est System.Array
. Nous avons toujours le changer en System.Collections.Generic.List
dans le Service de Référence de la boîte de dialogue Paramètres dans VS2008 pour des raisons de cohérence avec le reste de notre base de code.
Que faites-vous?
Vous devez vous connecter pour publier un commentaire.
ToList
toujours évalue la séquence immédiatement - et pas seulement dans LINQ to SQL. Si vous voulez, c'est très bien - mais il n'est pas toujours approprié.Personnellement, je voudrais essayer d'éviter de déclarer que vous revenez
List<T>
directement - généralementIList<T>
est plus approprié, et vous permet de changer de mise en œuvre plus tard. Bien sûr, il y a quelques opérations qui sont spécifiés surList<T>
lui-même... ce genre de décision est toujours délicat.EDIT: (j'aurais mis cela dans un commentaire, mais il serait trop encombrant.) Exécution différée vous permet de traiter les sources de données qui sont trop gros pour rentrer dans la mémoire. Par exemple, si vous êtes le traitement des fichiers journaux - la transformation d'un format à un autre, de les charger dans une base de données, l'élaboration des statistiques, ou quelque chose comme cela - vous pouvez très bien être capable de gérer arbitraire quantités de données en streaming, mais vous avez vraiment ne pas veux sucer tout en mémoire. Cela peut ne pas être une préoccupation pour votre application particulière, mais c'est quelque chose à garder à l'esprit.
Nous avons le même scénario de la WCF de communication à un serveur, le serveur utilise LINQtoSQL.
Que nous utilisons .ToArray() lors de la demande d'objets à partir du serveur, parce que c'est "illégal" pour le client de modifier la liste. (Sens, il n'y a pas de but à l'appui ".Ajouter", ".Supprimer", etc).
Bien que toujours sur le serveur, cependant, je vous recommande de le laisser tel qu'il est par défaut (ce qui n'est pas IEnumerable, mais plutôt IQueryable). De cette façon, si vous voulez filtrer encore plus en fonction de certains critères, le filtrage est ENCORE sur le SQL côté, jusqu'à ce évalués.
C'est un point très important, car cela signifie une performance incroyable des gains ou des pertes en fonction de ce que vous faites.
EXEMPLE:
Voyez-vous ce qui s'y passe? Le "GetClients" méthode pour forcer un téléchargement de TOUS les "clients" de la base de données... ALORS la clause where qui va se passer dans le GetClientsForLoogedInUser méthode à filtre vers le bas.
Maintenant, notez le léger changement:
Maintenant, l'évaluation réelle ne se produira pas avant ".ToArray" est appelé... et SQL fera le filtrage. BEAUCOUP mieux!
Dans le Linq-to-Objets de cas, le retour
List<T>
à partir d'une fonction n'est pas aussi beau que le retourIList<T>
, que LE VÉNÉRABLE SKEET points. Mais souvent, vous pouvez faire encore mieux que cela. Si la chose vous êtes de retour doit être immuable, IList est un mauvais choix, car il invite l'appelant à ajouter ou enlever des choses.Par exemple, parfois vous avez une méthode ou une propriété qui renvoie le résultat d'une requête Linq ou utilise
yield return
paresseusement générer une liste, et puis vous vous rendez compte qu'il serait préférable de le faire la première fois que vous êtes appelés, de mettre en cache le résultat dans unList<T>
et le retour de la version mise en cache par la suite. C'est lors du retour deIList
peut être une mauvaise idée, parce que l'appelant peut modifier la liste pour leurs propres fins, qui sera alors de corrompre le cache, ce qui rend leurs changements visibles pour tous les autres appelants.Mieux retourner
IEnumerable<T>
, de sorte que tout ce qu'ils ont est en avant de l'itération. Et si l'appelant veut rapide d'accès aléatoire, c'est à dire qu'ils souhaitent qu'ils pourraient utiliser [] pour accéder à l'indice, ils peuvent utiliserElementAt
, qui Linq définit alors qu'il renifle discrètement pourIList
et l'utilise que si elle est disponible, et si non, elle ne le muet linéaire de recherche.Une chose que j'ai utilisé
ToList
est quand j'ai un système complexe d'expressions Linq mélangé avec d'exploitants qui utilisentyield return
pour filtrer ou transformer des listes. L'exécution pas à pas dans le débogueur peut y faire très déroutant car il saute autour de faire l'évaluation différée, donc j'ai parfois ajouter temporairement un ToList() à quelques endroits afin que je puisse suivre plus facilement le chemin d'exécution. (Bien que si les choses que vous sont en cours d'exécution ont des effets secondaires, cela peut changer le sens du programme.)Cela dépend de si vous avez besoin de modifier la collection. J'aime utiliser un Tableau quand je sais que personne ne va à ajouter/supprimer des éléments. J'utilise une liste quand j'ai besoin de trier/ajouter/supprimer des éléments. Mais, en général, je laisse comme IEnumerable tant que je peux.
Si vous n'avez pas besoin d'y ajouter les fonctionnalités de la Liste<>, pourquoi ne pas simplement s'en tenir à IQueryable<> ?!?!?! Plus petit dénominateur commun est la meilleure solution (surtout quand on voit Timothée de réponse).