2009-03-10 4 views
5

J'essaie de comprendre LINQ et de devenir confiant à l'utiliser. Ce à quoi je me bats, ce sont les paramètres demandés. Exemple:Confus au sujet des paramètres LINQ

var sortedWords = words.OrderBy(a=>a.Length) 

words est une collection de matrices. IntelliSense de OrderBy dit:

Func<string, TKey> keyselector 

A func exécute une méthode et un string est la valeur, TKey une clé. Dans l'exemple http://msdn.microsoft.com/en-us/vcsharp/aa336756.aspx#thenBySimple (ThenBy - Comparer), nous comparons la longueur en disant a => a.Length. Je comprends cette syntaxe, mais en quoi est-ce lié à ce que l'intellisense demande?

J'ai tendance à trouver la signature de la méthode et l'intellisense illisibles à cause de tous les génériques.

Merci.

Répondre

5
a => a.Length 

Je comprends que la syntaxe, mais comment est-ce lié à ce que l'IntelliSense réclame?

Ce segment de code est une expression lambda.Une expression lambda est une méthode pratique pour générer une méthode anonyme (dans ce cas) ou une expression System.Linq.Expressions. Brisons-le par parties.

  • La caractéristique la plus notable est le =>, qui sépare les paramètres d'un corps de méthode.
  • Sur le côté gauche du =>, il y a un symbole: un. C'est la déclaration d'un paramètre pour notre méthode anonyme. Le compilateur est conscient que nous appelons OrderBy(), et que OrderBy nécessite un Func<string, object>. Le paramètre pour une telle fonction est une chaîne, donc le compilateur détermine que a doit être une chaîne. La seule chose que le programmeur doit fournir est un nom.
  • Sur le côté droit du =>, il existe un corps de méthode. Comme il s'agit d'un interligne, le mot-clé renvoie est implicite. L'EDI fournit une IntelliSense contre et une sous forme de chaîne, ce qui vous permet d'utiliser la propriété Length.

Maintenant, considérons ce C# 2.0 ...

IEnumerable<string> sortedWords = 
    Enumerable.OrderBy(words, delegate(string a) {return a.Length;}); 

Avec le C# 3,0

IEnumerable<string> sortedWords = words 
    .OrderBy(a => a.Length); 
+0

Merci pour cela. Cela prend tout son sens maintenant! :) – dotnetdev

+0

Aussi, si je devais d'abord obtenir la chaîne la plus courte, y a-t-il un moyen autre que de dire a => a.Length puis Reverse sur la collection? – dotnetdev

+0

Si vous souhaitez modifier les ordres de tri, consultez OrderBy, OrderByDescending, ThenBy et ThenByDescending. –

0

Je ne m'inquiète jamais vraiment de l'Intellisense, pour être honnête. Ça me gâtait tôt dans mon Linqage. Comme je passais plus de temps avec les génériques et les expressions, ça commençait à avoir du sens, mais jusqu'alors je me contentais de la syntaxe.

Ce qu'il veut est une expression lambda qui indique à Linq ce qu'il faut rechercher pour trier votre collection.

Je pense que vous, mon frère, vous accrochez là-dedans et cela aura du sens très bientôt.

6

Le type (tel qu'affiché par Intellisense) est logique si vous comprenez la nature de lambda expressions dans .NET/C#. Sinon, cela peut en effet sembler un peu étrange au nouveau venu. Commencez en considérant que le type de keySelector, Func < TSource, TKey > est simplement un délégué. Avant de C# 3.0, vous appelleriez une telle méthode en faisant passer un délégué en tant que paramètre, par exemple:

IEnumerable<string> sortedWords = words.OrderBy(new Func<string, int>(mySelectorMethod)); 

où mySelectorMethod est le nom d'une méthode ordinaire qui prend une chaîne comme paramètre et retourne un int. (En passant, je suppose que vous pourriez utiliser des délégués anonymes, mais n'allons pas là pour l'instant.) Notez également que cet exemple est purement illustratif, car LINQ est presque toujours utilisé avec .NET 3.5/C# 3.0 (bien que je crois il peut être utilisé avec/.NET 2.0/C# 2.0 - quelqu'un me corrige si je me trompe). Depuis C# 3.0, les méthodes peuvent être définies en ligne sous la forme d'expressions lambda, qui sont destinées à être utilisées précisément dans ces circonstances. Lisez l'article MSDN sur les expressions lambda (ci-dessus) si vous voulez obtenir une introduction correcte, mais je vais simplement décrire l'utilisation dans ce contexte spécifique. Comme vous dites, votre code (en C# 3.0) est quelque chose comme ce qui suit:

var sortedWords = words.OrderBy(a => a.Length); 

La partie de l'expression qui est a => a.Length est l'expression lambda, ce qui est vraiment juste un raccourci pour la déclaration d'une ligne de fonction. La syntaxe des expressions lambda est assez simple pour la plupart; à gauche de => les arguments sont spécifiés, généralement sous la forme (arg1, arg2, arg3), mais comme il n'y en a qu'un dans ce cas, vous pouvez omettre les parenthèses. A droite du => est l'expression qui est la valeur de retour de la fonction (expression lambda plus précisément).Vous pouvez également inclure le code réel avec une instruction return dans {et}, même si cela n'est généralement pas nécessaire. Ce que je crois que le compilateur C# reconnaît est le paramètre passé à OrderBy en tant qu'expression lambda, puis le compile dans une fonction et crée et transmet le délégué pour vous. Notez que les expressions lambda peuvent également être converties en System.Linq.Expressions.Expression objets (arborescences d'expression accessibles) au lieu de délégués, mais il s'agit d'une utilisation beaucoup moins courante. Quoi qu'il en soit, il se passe beaucoup de choses dans les coulisses ici, mais j'espère que cela devrait au moins clarifier pourquoi le type est Func < TSource, TKey > et comment il se rapporte à l'expression lambda. Comme je l'ai dit, lisez sur MSDN si vous voulez une meilleure compréhension de LINQ/lambdas/délégués ...

1

Je pense que l'IntelliSense est en fait très utile, en particulier pour les méthodes génériques qui prennent le type Func<..> comme argument, parce que vous peut voir les types et les types vous guider pour comprendre ce que la méthode pourrait faire.

Par exemple, les arguments pour OrderBy sont IEnumerable<string> comme argument 'this', ce qui signifie que nous avons une entrée contenant une collection de chaînes. Le premier argument keySelector a un type Func<string, TKey>, ce qui signifie que c'est une expression lambda que vous fournissez qui spécifie comment obtenir TKey de string. Cela suggère déjà que la méthode énumérera probablement tous les éléments (chaînes) de la collection et peut utiliser le keySelector pour obtenir la valeur du type TKey de chaque élément de la collection. Le nom TKey suggère déjà qu'il utilisera cette valeur pour comparer les éléments (chaînes) en utilisant cette clé calculée. Toutefois, si vous regardez l'autre surcharge qui prend IComparer<TKey> alors vous pouvez être sûr de cela - cet argument spécifie plus de détails sur la façon dont vous voulez comparer deux valeurs de type TKey, donc la fonction doit comparer les éléments en utilisant cette clé .

... ce genre de réflexion sur les types prend un peu de temps pour s'y habituer, mais une fois que vous l'apprendrez, cela peut être extrêmement utile. Il est plus utile dans le style « fonctionnel » du code, qui utilise souvent beaucoup de génériques et des expressions lamdba en C# 3.0 (et des choses similaires dans les langages fonctionnels comme F # ou autres)

+0

Pour me rendre plus claire. c'est vraiment la présentation et l'espacement de la phrase intellisense plutôt que toute autre chose qui le rend un peu dur pour l'œil. :) – dotnetdev

+0

Oui, je suis d'accord que ça pourrait être un peu plus clair. Je pense que c'est un peu difficile avec la syntaxe C#. Vous pouvez jeter un oeil à F #, qui (je pense) affiche des informations similaires de manière concise ... –

0

OrderBy() prend un délégué pour une fonction qui accepte un seul paramètre (dans votre cas, un string) et renvoie une valeur du type qui est remplacée par TKey. Il se peut que le type de paramètre (chaîne) était déjà déterminée depuis que vous avez appelé la méthode sur un IEnumerable<string> mais le type de délégué ne sera résolu que Func<string,int>après ce qu'il déduit de l'expression lambda quand il est entièrement spécifié (c'est-à-dire a => a.Length). Si vous n'avez pas fourni à l'analyseur d'indices sur ce que vous voulez en tant que clé de tri, cela affichera TKey dans IntelliSense jusqu'à ce qu'il puisse déterminer le type voulu.

Questions connexes