我有以下产品清单
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是我的Extension方法,但是当执行该行时,我从未调用过GET方法的断点?
由于
答案 0 :(得分:2)
使用yield return item;
时,您会返回一个枚举器,因此您应该执行以下操作:
foreach (var item in products.Get(IsVege))
{...}
或使用.ToList()
扩展方法为您执行foreach循环并返回项目列表。
但是通过编写以下代码:
var item = products.Get(IsVege);
您刚刚收到了适当的枚举器,用于遍历所需的集合。
请参阅此内容,了解如何调试yield return
代码:What is the yield keyword used for in C#?
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;
}
答案 1 :(得分:1)
LINQ和迭代器使用延迟执行。简而言之,yield
等待直到需要该值,然后继续执行。
veges1
包含查询,而非结果。仅当您对要求执行的查询的查询执行操作时才能完成工作。例如,为了向Count
提供veges1
,Get
需要完全执行。再举一个例子,如果你执行了veges1.First
,那么只需要执行Get
循环的第一次迭代。
强制执行查询的常用方法是使用ToList
:
// veges1 will now contain a List<Product> instead of an IEnumerable<Product>
var veges1 = products.Get(IsVege).ToList();
答案 2 :(得分:1)
致电时
var veges1 = products.Get(IsVege);
你只是向它提供一个匿名方法将在第一次迭代时执行。 IEnumerable - 是一个具有延迟执行的接口,这意味着在进行第一次迭代时将填充其内容。它只描述了您的行为,但没有实现它。您可以将代码更改为
var veges1 = products.Get(IsVege).ToList();
这将引导您进行方法的执行,因为ToList()将导致迭代的实现。
在方法之外构建更大的数据集时,IEnumerable很好,有时你可以避免使用iteratin。