2012-11-05 29 views
2

我對LINQ表達式的編譯和優化以及是否需要小心考慮表達式中let和where子句的順序感興趣。LINQ查詢優化:具體來說,讓子句位置重要嗎?

這裏是例子:

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只有在recordName等於「foobar」時才需要。將 DoSomethingIntensiveWith()爲每個記錄執行或只是記錄 其中recordName等於「foobar」?

如果我要確保DoSomethingIntensiveWith()只調用時 recordName等於「foobar的」,我還需要 where條款後的let 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); 
} 

同時,我要玩一些真實的代碼和調試器。我會 報告我找到的。

回答

2

如果這是LINQ到對象,那麼:是的,你這樣做。標準Enumerable.*實施是非常直接的應用程序的順序。你不需要所有的條款,但事情仍然按順序完成,而且順序是受到尊重的。如果它是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實現 - 它是從所述源數據到一個匿名類型使用INT的投影對於查詢。