如何在lambda表达式中“让”?

时间:2012-02-11 12:55:38

标签: linq entity-framework c#-4.0 lambda let

如何使用lambda表达式将此linq查询重写为Entity on? 我想在我的lambda表达式中使用 let 关键字或等效项。

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

对于一些类似的问题,例如我的问题所评论的内容,建议

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

将计算每个项目的AveragePrice,而在我提到的查询样式中, let 表达式阻止多次计算平均值。

4 个答案:

答案 0 :(得分:45)

因此,您可以使用扩展方法语法,这将涉及比您当前使用的更多lambda表达式。没有let,您只需使用多行lambda并声明一个变量:

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

请注意,我更改了平均价格比较,因为您的结果不会返回任何结果(超过500且低于250)。

替代方案是

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

答案 1 :(得分:24)

基本上,您需要使用Select和匿名类型将平均值添加到对象中,然后是语句的其余部分。

未经测试,但它应如下所示:

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

警告,请注意这些结构。使用let会在集合中为每个对象创建一个新的匿名类型,它会占用大量集合的大量内存  ...

在此查看详细信息: Let in chained extension methods

答案 2 :(得分:4)

另一种选择是定义这种扩展方法:

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

然后像这样编写你的查询:

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

答案 3 :(得分:1)

我们可以通过内联输出声明来避免其他所有答案中使用的lambda的开销:

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

并这样称呼

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