LINQ查询优化:具体来说,let子句的位置是否重要?

时间:2012-11-05 11:48:22

标签: c# .net linq

我对编译和优化LINQ表达式感兴趣,是否需要仔细考虑表达式中let和where子句的顺序。

以下是示例:

var query = 
    from record in Database.Table
    let recordName = record.GetName()
    let notUsed = UselessData()
    let stuff = DoSomethingIntensiveWith(record)
    where recordName == "foobar"
    select stuff;

foreach (string item in query) {
    Console.WriteLine("item => '{0}'", item);
}

问题/假设:

    必须解析
  • record.GetName()才能执行where 子句。
  • notUsed从未在表达式中使用,因此UselessData()将被调用 在所有?
  • 仅当stuff等于“foobar”时才需要
  • recordName。将 DoSomethingIntensiveWith()执行每条记录或只记录 recordName等于“foobar”?

如果我想确保DoSomethingIntensiveWith()仅在调用时调用 recordName等于“foobar”,我是否需要在let之后放置where caluse var query = from record in Database.Table let recordName = record.GetName() let notUsed = UselessData() where recordName == "foobar" let stuff = DoSomethingIntensiveWith(record) select stuff; foreach (string item in query) { Console.WriteLine("item => '{0}'", item); } 条款,如下:

{{1}}

与此同时,我将使用一些真正的代码和调试器。生病 报告我发现的内容。

1 个答案:

答案 0 :(得分:2)

如果这是LINQ-to-Objects,那么:是的,你这样做。标准Enumerable.*实施在按顺序应用方面非常直接。您不一定需要所有let条款,但事情仍按顺序完成,并且该顺序得到尊重。如果它是LINQ-to-anything-else,那么所有的赌注都会关闭。

这很容易证明:

using System;
using System.Linq;
class Foo
{
    public Foo(string value)
    {
        Value = value;
    }
    public string Value { get; private set; }
    public string Expensive()
    {
        Console.WriteLine(Value);
        return Value;
    }
    static void Main()
    {
        var foos = new[] {
            new Foo("abc"),
            new Foo("def")};
        Console.WriteLine("query1:");
        var query1 = (from obj in foos
                      let val = obj.Value
                      where val.StartsWith("a")
                      let result = obj.Expensive()
                      select result).ToArray();
        Console.WriteLine("query2:");
        var query2 = (from obj in foos
                      let val = obj.Value
                      let result = obj.Expensive()
                      where val.StartsWith("a")                      
                      select result).ToArray();    
    }
}

第一个查询过滤然后项目(因此它只对匹配记录执行昂贵的操作),而第二个查询计算两者的昂贵操作:

query1:
abc
query2:
abc
def

应该注意let实际上只是通过Select实现的 - 它是从源数据到查询内部使用的匿名类型的投影。