Linq和延期评估

当您使用LINQ定义可枚举集合时,无论是使用LINQ扩展方法还是使用查询运算符,应用程序实际上都不会在执行LINQ扩展方法时构建集合。 只有在迭代它时才会枚举该集合。 这意味着原始集合中的数据可以在执行LINQ查询和检索查询识别的数据之间进行更改; 您将始终获取最新的数据。

Microsoft Visual C#2013一步一步由John Sharp编写

我写了以下代码:

List numbers = new List() { 1, 2, 3, 4, 5 }; IEnumerable res = numbers.FindAll(a => a > 0).Select(b => b).ToList(); numbers.Add(99); foreach (int item in res) Console.Write(item + ", "); 

上面的代码的结果如下所示:

1,2,3,4,5,

为什么会这样? 我知道FuncActionPredicate但我无法弄清楚这里发生了什么。 基于上面的定义,代码是不合理的。

除了最后创建新集合的ToList()之外,还有另一个问题。

问题是你根本就没有使用LINQ。

FindAll不是LINQ扩展方法。

你应该使用Where

 List numbers = new List() { 1, 2, 3, 4, 5 }; IEnumerable res = numbers.Where(a => a > 0); numbers.Add(99); foreach (int item in res) Console.Write(item + ", "); 

首先设置一个包含1,2,3,4,5的int类型列表。 然后你使用linq来创建和定义枚举集合。 这里描述了linq如何工作:首先找到它们大于零的所有数字,因为你看到上面列表中的所有项都大于零,然后选择所有项并将它们放在一个列表中。 当您向数字列表中添加99时,它不会对定义的枚举集合产生影响,因为它将创建一个新集合并传递其中的项目,并且它没有对数字列表的任何引用。 你可以在linq表达式的末尾删除.ToList(),它将导致:1,2,3,4,5,99。

祝好运

ToList创建List实例并将所有项目复制到其中:

http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e276d6892241255b

  public static List ToList(this IEnumerable source) { if (source == null) throw Error.ArgumentNull("source"); return new List(source); } 

因此,如果你想在res99 ,你应该将它添加到res ,而不是numbers

  ... var res = numbers .Where(a => a > 0) // Filter out; Select is redundant .ToList(); res.Add(99); Console.Write(string.Join(", ", res)); 

ToList()实际上不是唯一的问题。 FindAll返回一个新列表。 所以当你打电话

 IEnumerable res = numbers.FindAll(a => a > 0) 

这跟做的一样

 IEnumerable newList = new List(); foreach (int old in numbers) { if (old > 0) newList.Add(old); } 

因此,当您向数字添加新项目时,它不再相关。 您正在搜索FindAll返回的列表而不是原始列表。

如果将ToList()操作推迟(或一起删除ToList()直到foreach循环,您将看到预期的结果。 ToList将执行与枚举相同的Linq表达式。

 List numbers = new List() { 1, 2, 3, 4, 5 }; IEnumerable res = numbers.FindAll(a => a > 0).Select(b => b); numbers.Add(99); foreach (int item in res) Console.Write(item + ", "); // another option, but not necessary in most cases... foreach (int item in res.ToList()) Console.Write(item + ", ");