C# 理解LINQ中的执行

C# 理解LINQ中的执行,c#,linq,C#,Linq,我有以下产品清单 List<Product> products = new List<Product> { new Product { ProductID = 1, ProductName = "first candy", UnitPrice = (decimal)10.0 }, ne

我有以下产品清单

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;
            }
        }
但在调试时的结果视图中,我看到了veges1的输出

如果我点击下面的代码

veges1.Count()   // Breakpoint in Predicate and GET is hit and i got the count value.
这是怎么回事?你能理解一下吗

PS:我知道这方面有很多例子和问题。我试图理解这个例子,因为它会让我更容易得到东西

更新问题 我在上面做的同一个示例正在尝试对Lamda表达式做同样的操作

var veges4 = products.Get(p => p.ProductName.Contains("vegetable"));
我得到了预期的结果

其中GET是我的扩展方法,但当执行该行时,从未调用GET方法上的断点

谢谢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();
//veges1现在将包含一个列表而不是IEnumerable
var veges1=products.Get(IsVege.ToList();

使用
退货项目时返回枚举数,因此应执行以下操作:

foreach (var item in products.Get(IsVege))
{...}
或者使用
.ToList()
扩展方法,该方法将为您执行foreach循环并返回项目列表。 但通过编写以下代码:

var item = products.Get(IsVege);
您刚刚收到用于遍历所需集合的正确枚举数

有关如何调试
yield return
代码的详细信息,请参见此:

public void Consumer()
{
foreach(整数()中的整数i)
{
Console.WriteLine(i.ToString());
}
}
公共IEnumerable整数()
{
收益率1;
收益率2;
收益率4;
收益率8;
收益率16;
收益率16777216;
}
当你打电话时

var veges1 = products.Get(IsVege);
您只需指定一个匿名方法,它将在第一次迭代时执行。IEnumerable是一个延迟执行的接口,这意味着在您进行第一次迭代时,它的内容将被填充。它只是描述您的行为,而不是实现它。您可以将代码更改为

var veges1 = products.Get(IsVege).ToList();
这将导致方法的执行,因为ToList()将导致迭代的实现


IEnumerable在方法之外构建更大的数据集时很好,有时可以避免迭代。

可能很傻。.Count函数如何知道调用哪个扩展方法并传递谓词?延迟执行。。好啊我的疑问是如何在var veges1=products.get(IsVege)的结果视图中获得o/p;线executed@user2067567:Get返回由编译器创建的特殊数据类型。此数据类型包含转换为状态机的
Get
代码。这允许Count和其他方法执行
Get
@user2067567:Use
ToList
的单个步骤。我已经扩展了我的答案。@user2067567:我不明白你的补充问题。
var veges1 = products.Get(IsVege);
var veges1 = products.Get(IsVege).ToList();