[英]Understanding Deferred Execution: Is a Linq Query Re-executed Everytime its collection of anonymous objects is referred to?
[英]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
包含查詢 ,而不是結果。 當你需要要執行的查詢的查詢執行的操作工作才完成。 例如,為了給你veges1
的Count
, Get
需要完全執行。 另一個例子,如果你執行了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.