簡體   English   中英

了解LINQ中的執行

[英]Understanding Execution in LINQ

我有以下產品清單

List<Product> products = new List<Product> {
                new Product { 
                    ProductID = 1, 
                    ProductName = "first candy", 
                    UnitPrice = (decimal)10.0 },
                new Product { 
                    ProductID = 2, 
                    ProductName = "second candy", 
                    UnitPrice = (decimal)35.0 },
                new Product { 
                    ProductID = 3, 
                    ProductName = "first vegetable", 
                    UnitPrice = (decimal)6.0 },
                new Product { 
                    ProductID = 4, 
                    ProductName = "second vegetable", 
                    UnitPrice = (decimal)15.0 },
                new Product { 
                    ProductID = 5, 
                    ProductName = "third product", 
                    UnitPrice = (decimal)55.0 }
            };

var veges1 = products.Get(IsVege);   //Get is a Extension method and IsVege is a Predicate

//Predicate
 public static bool IsVege(Product p)
        {
            return p.ProductName.Contains("vegetable");
        }

//Extension Method
public static IEnumerable<T> Get<T>(this IEnumerable<T> source, Func<T, bool> predicate)
        {
            foreach (T item in source)
            {
                if (predicate(item))
                    yield return item;
            }
        }

我知道這些主題已經很晚了,但我仍然試圖通過Visual Studio中的調試來理解

我在所有函數中都有斷點(謂詞,擴展方法)

我的問題是

1.當下面的行被執行時會發生什么

var veges1 = products.Get(IsVege);   // i dont see the breakpoint hitting either predicate or GET method)

但在調試時我的結果視圖中我看到了veges1的輸出。

如果我點擊下面的代碼

veges1.Count()   // Breakpoint in Predicate and GET is hit and i got the count value.

這是如何運作的 ? 你能理解一下嗎?

PS:我知道有很多例子和問題。 我試圖通過這個例子來理解,因為它會讓我更容易理解。

更新的問題

我上面做的同樣的樣本試圖用Lamda Expression做同樣的事情

var veges4 = products.Get(p => p.ProductName.Contains("vegetable"));

我得到了預期的結果。

其中GET是我的擴展方法,但是當執行該行時,我從未調用過GET方法的斷點?

謝謝

使用yield return item; 你返回一個枚舉器,所以你應該做這樣的事情:

foreach (var item in products.Get(IsVege))
{...}

或者使用.ToList()擴展方法,它將為您執行foreach循環並返回項目列表。 但是通過編寫以下代碼:

var item = products.Get(IsVege);

你剛剛收到了適當的枚舉器來遍歷所需的集合。

有關如何調試yield return代碼的好處,請參閱此內容: C#中使用的yield關鍵字是什么?

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}

LINQ和迭代器使用延遲執行 簡而言之, yield等待直到需要該值, 然后繼續執行。

veges1包含查詢 ,而不是結果。 當你需要要執行的查詢的查詢執行的操作工作才完成。 例如,為了給你veges1CountGet需要完全執行。 另一個例子,如果你執行了veges1.First ,那么只需要執行Get循環的第一次迭代。

強制執行查詢的常用方法是使用ToList

// veges1 will now contain a List<Product> instead of an IEnumerable<Product>
var veges1 = products.Get(IsVege).ToList();

你打電話的時候

var veges1 = products.Get(IsVege);

你只需要一個匿名方法,它將在第一次迭代時執行。 IEnumerable - 是一個具有延遲執行的接口,這意味着在進行第一次迭代時將填充其內容。 它只描述了您的行為,但沒有實現它。 您可以將代碼更改為

var veges1 = products.Get(IsVege).ToList();

這將引導您執行您的方法,因為ToList()將導致您的迭代的實現。

當在方法之外構建更大的數據集時,IEnumerable是好的,有時您可以避免使用iteratin。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM