C#,lambda:如何处理冗余调用?

时间:2019-11-27 11:50:06

标签: c# lambda

我对编译器如何处理以下表达式感到好奇:

    var collapsed = elements.GroupBy(elm => elm.OrderIdentifier).Select(group => new ModelsBase.Laser.Element()
    {
        CuttingDurationInSeconds = group.Sum(itm => itm.CuttingDurationInSeconds),
        FladderDurationInSeconds = group.Sum(itm => itm.FladderDurationInSeconds),
        DeliveryDate = group.Min(itm => itm.DeliveryDate),
        EfterFladderOpstilTid = group.First().EfterFladderOpstilTid,
        EfterRadanOpstilTid = group.First().EfterRadanOpstilTid,
    });

如您所见,我正在使用两次组总和,所以没有人知道“组”列表是否将被重复两次以获取两个总和,或者是否将其优化,因此实际上只有1个完整的迭代列表。

3 个答案:

答案 0 :(得分:2)

LINQ通常不是实现高性能的最佳方法,您获得的是编程效率,无需太多行代码即可获得结果。

优化的可能性有限。对于SQL查询,有一个经验法则:一个查询胜于两个查询。

1)到SQL_Server只有一次往返

2)使SQL Server可以优化那些查询,如果服务器知道下一步要做什么,优化就会变得更好。优化是针对每个查询完成的,而不是针对多个查询。

如果使用Linq to Objects,构建庞大的查询绝对没有收益。 如您的示例所示,它可能会导致多次迭代。您可以使代码更简单,更易于阅读-但您放弃了控制权,因此放弃了性能。

答案 1 :(得分:1)

编译器当然不会对其进行优化。

如果这是使用LINQ to Objects,因此是委托,则委托将对5个属性的每个组进行5次迭代。

如果这是使用LINQ to SQL,Entity Framework或类似的东西,因此是表达式树,那么基本上取决于查询提供者来适当地优化它。

答案 2 :(得分:1)

您可以通过在分组键中添加两个字段来优化请求

var collapsed = elements.GroupBy(elm => new{
   OrderIdentifier=elm.OrderIdentifier,
   EfterFladderOpstilTid=elm.EfterFladderOpstilTid,
   EfterRadanOpstilTid=elm.EfterRadanOpstilTid
})
   .Select(group => new ModelsBase.Laser.Element()
        {
            CuttingDurationInSeconds = group.Sum(itm => itm.CuttingDurationInSeconds),
            FladderDurationInSeconds = group.Sum(itm => itm.FladderDurationInSeconds),
            DeliveryDate = group.Min(itm => itm.DeliveryDate),
            EfterFladderOpstilTid = group.Key.EfterFladderOpstilTid,
            EfterRadanOpstilTid   = group.Key.EfterRadanOpstilTid,
        });

或者通过使用LET语句

var collapsed = from groupedElement in 
                        (from element in elements
                         group  element by element.OrderIdentifier into g
                        select g)
                        let First = groupedElement.First()
                        select  new ModelsBase.Laser.Element()
                        {
                            CuttingDurationInSeconds = groupedElement.Sum(itm => itm.CuttingDurationInSeconds),
                            FladderDurationInSeconds = groupedElement.Sum(itm => itm.FladderDurationInSeconds),
                            DeliveryDate = groupedElement.Min(itm => itm.DeliveryDate),
                            EfterFladderOpstilTid = First.EfterFladderOpstilTid,
                            EfterRadanOpstilTid = First.EfterRadanOpstilTid
                        };