44 votes

Comment utiliser "let" dans une expression lambda ?

Comment puis-je réécrire cette requête linq en Entity on avec une expression lambda ?
Je veux utiliser let ou un équivalent dans mon expression lambda.

var results = from store in Stores
              let AveragePrice =  store.Sales.Average(s => s.Price)
              where AveragePrice < 500 && AveragePrice > 250

Pour des questions similaires à celle qui est commentée sous ma question, il est suggéré de

.Select(store=> new { AveragePrice = store.Sales.Average(s => s.Price), store})

qui calculera le prix moyen pour chaque article, tandis que dans le style de requête que j'ai mentionné, let empêche de calculer la moyenne plusieurs fois.

48voto

Jay Points 27907

Vous pouvez donc utiliser la syntaxe de la méthode d'extension, ce qui implique une expression lambda de plus que celle que vous utilisez actuellement. Il n'y a pas de let il suffit d'utiliser un lambda à plusieurs lignes et de déclarer une variable :

var results = Stores.Where(store => 
{
    var averagePrice = store.Sales.Average(s => s.Price);
    return averagePrice > 250 && averagePrice < 500;
});

Notez que j'ai modifié la comparaison des prix moyens, car la vôtre ne renvoie jamais aucun résultat (plus de 500 ET moins de 250).

L'alternative est

var results = Stores.Select(store => new { Store = store, AveragePrice = store.Sales.Average(s => s.Price})
    .Where(x => x.AveragePrice > 250 && x.AveragePrice < 500)
    .Select(x => x.Store);

27voto

Yoeri Points 944

En gros, vous devez utiliser Select et un type anonyme pour ajouter la moyenne à votre objet, puis le reste de votre déclaration.

Non testé mais ça devrait ressembler à ça :

Stores.Select(
x => new { averagePrice = x.Sales.Average(s => s.Price), store = x})
.Where(y => y.averagePrice > 500 && y.averagePrice < 250)
.Select(x => x.store);

Attention, soyez prudent avec ces constructions. L'utilisation de let crée un nouveau type anonyme par objet dans votre collection, cela consomme beaucoup de mémoire avec de grandes collections ...

Regardez ici pour plus de détails : Laisser dans les méthodes d'extension chaînées

4voto

Timothy Shields Points 17970

Une autre option consiste à définir cette méthode d'extension :

public static class Functional
{
    public static TResult Pipe<T, TResult>(this T value, Func<T, TResult> func)
    {
        return func(value);
    }
}    

Ensuite, écrivez votre requête comme ceci :

var results = Stores
    .Where(store => store.Sales.Average(s => s.Price)
        .Pipe(averagePrice => averagePrice < 500 && averagePrice > 250));

1voto

daw Points 381

Nous pouvons éviter la surcharge de la lambda utilisée dans toutes les autres réponses avec une déclaration inline out :

public static class FunctionalExtensions
{
    public static T Assign<T>(this T o, out T result) =>
        result = o;
}

Et appelez-le comme ceci

var results = Stores
    .Where(store => store.Sales
        .Average(s => s.Price)
        .Assign(out var averagePrice) < 500 && averagePrice > 250);

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