25 votes

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 un IEnumerable<> ou peut-être un IOrderedEnumerable<>. Nous avons constaté qu'un 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 d' 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 l' IEnumerable prématurément.

Nous sommes également en utilisant WCF largement, la valeur par défaut type de collection de 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?

23voto

Jon Skeet Points 692016

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 - habituellement IList<T> plus appropriée 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 sur List<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 n'avez pas envie de le 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.

16voto

Timothy Khouri Points 14640

Nous avons le même scénario de la WCF de communication à un serveur, le serveur utilise LINQtoSQL.

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 TOUJOURS 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:

// This is just an example... imagine this is on the server only. It's the
// basic method that gets the list of clients.
private IEnumerable<Client> GetClients()
{
    var result = MyDataContext.Clients;  

    return result.AsEnumerable();
}

// This method here is actually called by the user...
public Client[] GetClientsForLoggedInUser()
{
    var clients = GetClients().Where(client=> client.Owner == currentUser);

    return clients.ToArray();
}

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:

private IQueryable<Client> GetClients()
{
    var result = MyDataContext.Clients;  

    return result.AsQueryable();
}

Maintenant, l'évaluation réelle ne se produira pas avant ".ToArray" est appelé... et SQL fera le filtrage. BEAUCOUP mieux!

7voto

Daniel Earwicker Points 63298

Dans le Linq-to-Objets de cas, de revenir List<T> à partir d'une fonction n'est pas aussi beau que le retour IList<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 en List<T> et le retour de la version mise en cache par la suite. C'est lors du retour de la IList 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 utiliser ElementAt, ce qui Linq définit alors qu'il renifle discrètement pour IList 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 pour, c'est quand j'ai un système complexe d'expressions Linq mélangé avec d'exploitants qui utilisent yield return de 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.)

2voto

joegtp Points 562

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.

2voto

TheSoftwareJedi Points 15921

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).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X