繁体   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