2010-08-18 51 views
2

這是根據是否有一些匹配的ID來返回布爾值。IQueryable.Where()實際發生了什麼?

from t in getAll 
select new Result 
{ 
...    
    bool DetailsAvailable = 
     (db.SaveTrackings.Where(s => s.BundleID == t.bundleID 
            && s.UserID == t.userID) 
         .Count() > 0) ? true : false; 
} 

這就是我想明白了:.Where()將返回所有匹配的ID的條目,然後.Count()只是看到究竟有多少。我只是覺得我有一半明白我們需要s

我知道從這段代碼中可以期待什麼,因爲它已經被使用了,我只是不明白它是如何工作的,MSDN中的一些文檔使用了一些令我困惑的術語。

所有lambda表達式使用拉姆達 運算符=>,它讀作 「去 於」。 lambda 運算符的左側指定輸入 參數(如果有的話),並且右側 包含表達式或語句 塊。 lambda表達式x => x * x被讀取爲「x轉到x次x」。

所以怎麼了,我想明白了什麼我的代碼意味着在此基礎上,.Where(s「變爲」 s.BundleID == t.BundleID ...),所以這裏發生了什麼? 「去」是什麼意思?是否將s中的每個ID與t中的每個ID進行比較?我怎麼理解爲什麼它被稱爲「去」和究竟發生了什麼?

然後它變得更加撲朔迷離......

=>運算符具有相同的優先級 如賦值(=),是 右結合。

Lambdas用於基於方法的LINQ 查詢作爲標準查詢的參數 運算符方法(如Where)。

當您使用基於方法的語法來調用 Where方法在 枚舉類(如你在LINQ做 對象和LINQ to XML)的參數 是委託類型System.Func。拉姆達表達式是創建 委託的最方便的方式。

什麼是代表類型System.Func<T, TResult>以及它是如何使用此「去」運算符創建的?

我不能只是使用代碼,因爲我知道它的工作,我需要了解如何/爲什麼。

+2

如果您真的只需要一個true或false,那麼使用Any函數而不是where + count可能更有效?一旦一個項目爲真,db.SaveTrackings.Any(相同的謂詞)將立即返回true。 – 2010-08-18 16:03:08

+0

@John謝謝,如果我只能理解這個整個委託/ lambda事件發生了什麼,試圖讓我的頭在 – BigOmega 2010-08-18 18:01:44

+0

位,它會花一點時間,然後它只會「點擊」。最簡單的方法就是將它們視爲沒有名字的迷你函數。語法可能會有點奇怪,特別是沒有參數...()=> {等等等等等等等等等等等等。 WTH是那樣的!:D – 2010-08-19 15:54:36

回答

2

也許這將有助於看到這個功能通過手工來實現:

using System; 
using System.Collections.Generic; 

namespace CSharpSandbox 
{ 
    class Program 
    { 
     static IEnumerable<T> Where<T>(IEnumerable<T> input, Func<T, bool> predicate) 
     { 
      foreach (T item in input) 
      { 
       if (predicate(item)) 
        yield return item; 
      } 
     } 

     static void Main(string[] args) 
     { 
      int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
      IEnumerable<int> evens = Where(numbers, n => n % 2 == 0); 
      foreach (int even in evens) 
      { 
       Console.WriteLine(even); 
      } 
     } 
    } 
} 

構建體name => someEvaluation創建匿名函數,由以下部分組成:

  • name是一個簡單的參數的名稱,它的類型是從它的使用推斷。您需要一個名稱,以便您可以引用該函數中傳遞的參數。
  • =>是您的匿名函數體的開始,正文的範圍是單個表達式。
  • someEvaluation是由單個表達式組成的匿名函數的主體。

在我們的情況下,Func<T, bool>限定函數,它接受T類型的單個參數,並返回bool類型的輸出。 (如果我們使用Func<T, U, bool>,我們會採取T型和U的兩個輸入,並返回一個bool。在Func定義的最後一個類型參數的返回值。)

您可以準確地調用的Func實例作爲你調用任何其他函數。如果函數使用參數,則按照預期將它們傳入,參數將綁定到您定義的變量名稱。當你調用該函數時,控制流將跳轉到你的函數中並評估其結果。

原則上,您不需要匿名創建Func。您可以通過任何具有兼容類型簽名的功能,例如:

static bool IsEven(int n) 
    { 
     return n % 2 == 0; 
    } 

    static void Main(string[] args) 
    { 
     int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
     IEnumerable<int> evens = Where(numbers, IsEven); 
     foreach (int even in evens) 
     { 
      Console.WriteLine(even); 
     } 
    } 

該程序產生相同的輸出。事實上,在幕後,語法name => expression是語法糖;當它被編譯時,C#將生成一個帶有隱藏名稱的私有函數,並將其轉換爲上面的格式。

+0

也許這也會有所幫助:http://stackoverflow.com/questions/2294053/explaining-functional-programming-to-object-oriented-programmers-and-less-technic/2294279#2294279 – Juliet 2010-08-18 18:29:12

+0

等一下。用你的第一個例子,你寫出了一個函數。這僅僅是爲了證明發生了什麼,或者這是否真的如何實現?因爲我得到了正在發生的事情,我只是不明白。例如,如果我做了一個cout >>計算機告訴顯卡將文本吐出到我的顯示器上。但是我不知道這些事情是怎麼發生的,我只知道他們工作。 – BigOmega 2010-08-19 23:39:34

+0

@Ryan:是的,上面的函數真的*是*你如何實現Where函數。它不清楚你不瞭解哪部分。對於它的價值,大多數C#都充滿語法糖,偶爾可能會掩蓋底層實現細節。一個包含'yield return whatever'的函數被轉換爲一個實現'IEnumerable '的類,它本身就是一個狀態機,每次調用它的枚舉器的MoveNext()函數時它都會轉移到下一步。 (...) – Juliet 2010-08-20 00:25:46

2

如果有幫助,請將s作爲SaveTracking類型的變量。它正在迭代您收集/表中的每個s,並測試其BundleID的值。

t是一樣的想法 - 就像它遍歷所有getAll的返回集合。

這就像SQL僞代碼:

SELECT * FROM SaveTracking INNER JOIN GetAll 
    ON BundleID AND UserID 

對於正在發生的事情與lambda表達式,檢查出Jon Skeet's book C# In Depth有更深入的技術說明。第9章,第230頁。我發現這本書很有幫助。

+0

這雖然沒有幫助,但因爲我已經理解了,並且有'像這樣想'這個例子不是我所需要的,我想知道計算機究竟是做什麼而不是做什麼行爲是 – BigOmega 2010-08-18 18:03:36

0

Lambda表達式只是縮短了代碼的方式,但它確實一模一樣的事情,宣稱對應委託類型System.Func<T, TResult>

我相信C#你蘭巴轉換爲方法在後臺運行的方法編譯和它看起來像這樣:

bool LambdaExpression(YourType s) 
{ 
    return s.BundleID == t.bundleID && s.UserID == t.userID; 
} 
相關問題