Code équivalent au mot clé "let" dans les appels de méthode d'extension LINQ chaînés

193

En utilisant les fonctionnalités de compréhension des requêtes des compilateurs C #, vous pouvez écrire du code comme:

var names = new string[] { "Dog", "Cat", "Giraffe", "Monkey", "Tortoise" };
var result =
    from animalName in names
    let nameLength = animalName.Length
    where nameLength > 3
    orderby nameLength
    select animalName; 

Dans l'expression de requête ci-dessus, le letmot - clé permet à une valeur d'être transmise aux opérations where et orderby sans appels dupliqués à animalName.Length.

Quel est l'ensemble équivalent d'appels de méthode d'extension LINQ qui réalise ce que le mot-clé "let" fait ici?

LBushkin
la source
11
Pour info, la spécification C # 3.0 explique chaque règle de traduction de compréhension de requête avec des détails atroces.
Eric Lippert
17
et pour ceux qui trouvent les spécifications lourdes, C # in Depth de Jon Skeet le couvre aussi ;-p
Marc Gravell
Les spécifications du langage C # sont des documents Word téléchargeables dont le contenu n'est pas indexé par les moteurs de recherche et n'est ni lisible ni consultable en ligne. Ce serait d'une grande aide si les spécifications étaient disponibles en ligne.
Olivier Jacot-Descombes

Réponses:

255

Let n'a pas sa propre opération; il se chevauche Select. Vous pouvez voir cela si vous utilisez "réflecteur" pour séparer une DLL existante.

ce sera quelque chose comme:

var result = names
        .Select(animalName => new { nameLength = animalName.Length, animalName})
        .Where(x=>x.nameLength > 3)
        .OrderBy(x=>x.nameLength)
        .Select(x=>x.animalName);
Marc Gravell
la source
4
Woah, je ne savais pas que vous pouviez encapsuler automatiquement en utilisant le nouvel opérateur comme ça.
David Pfeffer
19
Vous pouvez également utiliser le petit bouton "lambda" dans le volet de résultats de LinqPad pour voir le code généré si vous démarrez avec un Queryable. En d'autres termes, si vous changez votre première ligne en var names = new string [] {"Dog", ...} .AsQueryable (); puis lancez le tout dans LinqPad, cliquez sur le petit bouton lambda, vous verrez le code généré pratiquement identique à la réponse de Marc.
Reb.Cabin
3
J'avais besoin d'utiliser la .Dump()méthode d'extension dans LinqPad pour voir le lambda résultant.
justanotherdev
89

Il y a un bon article ici

Crée essentiellement letun tuple anonyme. C'est équivalent à:

var result = names.Select(
  animal => new { animal = animal, nameLength = animal.Length })
.Where(x => x.nameLength > 3)
.OrderBy(y => y.nameLength)
.Select(z => z.animal);
Keltex
la source
Je cite l'article ciit seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
JB. Avec Monica.
Je le cite plus loin:This could be considered a micro-optimisation
Monseigneur le
7

Il existe également une méthode d'extension .Let dans System.Interactive, mais son objectif est d'introduire une expression lambda à évaluer «en ligne» dans une expression fluide. Par exemple, considérons (dans LinqPad, par exemple) l'expression suivante qui crée de nouveaux nombres aléatoires à chaque fois qu'elle est exécutée:

var seq = EnumerableEx.Generate(
    new Random(),
    _ => true,
    _ => _,
    x => x.Next());

Pour voir que de nouveaux échantillons aléatoires apparaissent à chaque fois, considérez ce qui suit

seq.Zip(seq, Tuple.Create).Take(3).Dump();

ce qui produit des paires dans lesquelles la gauche et la droite sont différentes. Pour produire des paires dans lesquelles la gauche et la droite sont toujours les mêmes, procédez comme suit:

seq.Take(3).ToList().Let(xs => xs.Zip(xs, Tuple.Create)).Dump(); 

Si nous pouvions invoquer directement des expressions lambda, nous pourrions écrire

(xs => xs.Zip(xs, Tuple.Create))(seq.Take(3).ToList()).Dump();

Mais nous ne pouvons pas invoquer des expressions lambda comme s'il s'agissait de méthodes.

Reb.Cabin
la source
1

about Code équivalent au mot clé 'let' dans les appels de méthode d'extension LINQ chaînés

le commentaire ci-dessus n'est plus valide

var x = new List<int> { 2, 3, 4, 5, 6 }.AsQueryable();
(from val in x
let val1 = val
let val2 = val + 1
where val2 > val1
select val
).Dump();

produit

System.Collections.Generic.List`1[System.Int32]
.Select(
  val =>
     new
     {
         val = val,
         val1 = val
     }
)
.Select(
  temp0 =>
     new
     {
         temp0 = temp0,
         val2 = (temp0.val + 1)
     }
)
.Where(temp1 => (temp1.val2 > temp1.temp0.val1))
.Select(temp1 => temp1.temp0.val)

donc plusieurs letsont optimisés maintenant

Pas important
la source