2012-12-27 47 views
1

我通過101個的LINQ教程從這裏編碼:LINQ:單獨排序依據和thenby聲明

http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

大多數例子很簡單,但是這一次扔我一個循環:

[Category("Ordering Operators")] 
    [Description("The first query in this sample uses method syntax to call OrderBy and ThenBy with a custom comparer to " + 
       "sort first by word length and then by a case-insensitive sort of the words in an array. " + 
       "The second two queries show another way to perform the same task.")] 
    public void Linq36() 
    { 
     string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry", "b1" }; 

     var sortedWords = 
      words.OrderBy(a => a.Length) 
       .ThenBy(a => a, new CaseInsensitiveComparer()); 

     // Another way. TODO is this use of ThenBy correct? It seems to work on this sample array. 
     var sortedWords2 = 
      from word in words 
      orderby word.Length 
      select word; 

     var sortedWords3 = sortedWords2.ThenBy(a => a, new CaseInsensitiveComparer()); 

無論我把它放在哪個單詞的哪個組合長度始終是第一個排序標準......即使我不知道第二個語句(沒有orderby!)知道原來的order by子句是什麼。

我會瘋了嗎?任何人都可以解釋Linq如何「記住」原始排序是什麼?

+0

你可能想重新提出你的問題。我不確定你在這裏問什麼。 –

+0

@JustinNiessner它對我來說非常有意義...... – Servy

+2

它「記住」,因爲在這兩種情況下,這正是你告訴它做的。選擇,訂購,然後。我會說你會瘋了。 –

回答

4

返回類型OrderBy不是IEnumerable<T>。這是IOrderedEnumerable<T>。這是一個「記住」所有給定順序的對象,只要你不調用另一種方法將變量轉換回IEnumerable,它就會保留這些知識。

請參閱Jon Skeets精彩的博客系列Eduling,其中他重新實現了Linq-to-objects以獲取更多信息。在OrderBy/ThenBy的主要項目有:

+0

但他使用'var'因此'sortedWords2'的類型將是'IOrderedEnumerable ' –

+1

@lazyberezovsky right,fixed。我很驚訝我自己,編譯器足夠聰明,在這種情況下動態地確定正確的返回類型。 – Servy

1

這是因爲LINQ是懶惰的,第一即當您列舉的順序所有的評價僅發生..表達已經構建的樹被執行。

1

你的問題在表面上並沒有什麼意義,因爲你沒有考慮延遲執行的性質。在任何情況下它都不會「記住」,它只是在真正需要時纔會執行。如果你在調試器中運行你的例子,你會發現它們會產生相同的結構聲明。考慮:

var sortedWords = 
     words.OrderBy(a => a.Length) 
      .ThenBy(a => a, new CaseInsensitiveComparer()); 

您已明確告知它OrderBy,ThenBy。每個語句被堆疊,直到他們全部完成,並最終查詢構造看起來像(僞):

Select from sorted words, order by length, order by comparer 

然後,一旦這是所有準備去執行它,並放入sortedWords。現在考慮:

var sortedWords2 = 
     from word in words 
     orderby word.Length // You're telling it to sort here 
     select word; 

// Now you're telling it to ThenBy here 
var sortedWords3 = sortedWords2.ThenBy(a => a, new CaseInsensitiveComparer()); 

然後,一旦這些查詢堆積起來,它將被執行。但是,它不會被執行,直到你需要它們。 sortedWords3在您採取行動之前不會有任何價值,因爲需要延期。因此,在這兩種情況下,你基本上說來編譯:

  1. 等待,直到我完成了由比較器建立我的查詢
  2. 選擇從源
  3. 訂購長度
  4. 然後
  5. 好的,你的東西。

注意:總之,LINQ不會「記住」,它只是在您完成指令執行後才執行。然後它將它們堆疊成一個查詢,並在需要時立即運行它們。