简体   繁体   English

了解LINQ中的执行

[英]Understanding Execution in LINQ

I have Following list of products 我有以下产品清单

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;
            }
        }

I know am very late on these topics but still am trying to understand by debugging in Visual Studio 我知道这些主题已经很晚了,但我仍然试图通过Visual Studio中的调试来理解

i have break point in all the functions(Predicate,Extension Method) 我在所有函数中都有断点(谓词,扩展方法)

My question is 我的问题是

1.What happens when the below line gets executed 1.当下面的行被执行时会发生什么

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

But in my results view while debugging i see output for veges1. 但在调试时我的结果视图中我看到了veges1的输出。

If i hit the below code 如果我点击下面的代码

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

How does this work ? 这是如何运作的 ? Can you give some understanding. 你能理解一下吗?

PS: i know there are lot of examples and questions on this. PS:我知道有很多例子和问题。 Am trying to understand with this example as it ll make me easier to get things. 我试图通过这个例子来理解,因为它会让我更容易理解。

Updated Question 更新的问题

The same sample i did above am trying to do the same with Lamda Expression 我上面做的同样的样本试图用Lamda Expression做同样的事情

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

and i get results as expected. 我得到了预期的结果。

where GET is my Extension method but when that line is executed my break points on GET method was never called? 其中GET是我的扩展方法,但是当执行该行时,我从未调用过GET方法的断点?

Thanks 谢谢

When using yield return item; 使用yield return item; you return an Enumerator so you should do something like this: 你返回一个枚举器,所以你应该做这样的事情:

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

or use .ToList() extension method that will do the foreach loop for you and return a list of items. 或者使用.ToList()扩展方法,它将为您执行foreach循环并返回项目列表。 but by writing the following code: 但是通过编写以下代码:

var item = products.Get(IsVege);

you just received the proper enumerator for traversing the desired collection. 你刚刚收到了适当的枚举器来遍历所需的集合。

see this for a good referance on how to debug the yield return code: What is the yield keyword used for in C#? 有关如何调试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 and iterators use deferred execution . LINQ和迭代器使用延迟执行 In a nutshell, yield waits until the value is needed and then continues execution. 简而言之, yield等待直到需要该值, 然后继续执行。

veges1 contains a query , not a result. veges1包含查询 ,而不是结果。 Work is done only when you perform an operation on the query that requires the query to be executed . 当你需要要执行的查询的查询执行的操作工作才完成。 For example, to give you the Count of veges1 , Get needs to be executed fully. 例如,为了给你veges1CountGet需要完全执行。 As another example, if you executed veges1.First , only the first iteration of your Get loop would need to be executed. 另一个例子,如果你执行了veges1.First ,那么只需要执行Get循环的第一次迭代。

A common way to force execution of your query is to use ToList : 强制执行查询的常用方法是使用ToList

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

When you call 你打电话的时候

var veges1 = products.Get(IsVege);

you just assing to it an anonymous method will be executed on its first iteration. 你只需要一个匿名方法,它将在第一次迭代时执行。 IEnumerable - is an interface with deferred execution, and that means that its content will be filled when you make your first iteration. IEnumerable - 是一个具有延迟执行的接口,这意味着在进行第一次迭代时将填充其内容。 It just describes your behavior, but not implements it. 它只描述了您的行为,但没有实现它。 You can change your code to 您可以将代码更改为

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

This will lead you to the executon of your method, because ToList() will cause the implementation of your iteration. 这将引导您执行您的方法,因为ToList()将导致您的迭代的实现。

IEnumerable are good when building a larger set of data outside the method, and sometimes you can avoid of iteratin it. 当在方法之外构建更大的数据集时,IEnumerable是好的,有时您可以避免使用iteratin。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM