Linq和延期评估
本文关键字:评估 Linq | 更新日期: 2023-09-27 18:03:01
使用LINQ定义可枚举集合时,无论是使用LINQ扩展方法还是使用查询运算符,应用程序在LINQ执行扩展方法;只有当您对其进行迭代。这意味着原始中的数据集合可以在执行LINQ查询和检索之间更改查询所标识的数据;你总是能拿到最多的最新数据
Microsoft Visual C#2013由John Sharp逐步编写
我已经写了以下代码:
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<int> 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,
为什么会这样?我知道Func
、Action
和Predicate
,但我不知道这里发生了什么。基于上述定义,代码是不合理的。
除了末尾的ToList()
正在创建一个新集合之外,还有另一个问题。
问题是您根本没有使用LINQ。
FindAll
不是LINQ扩展方法。
您应该使用Where
:
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<int> 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<T>
的新实例,并将所有项目复制到其中:
http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e276d6892241255b
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
return new List<TSource>(source);
}
因此,如果你想在res
中有99
,你应该把它添加到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<int> res = numbers.FindAll(a => a > 0)
这和是一样的
IEnumerable<int> newList = new List<int>();
foreach (int old in numbers) {
if (old > 0) newList.Add(old);
}
因此,当你在数字中添加一个新项目时,它就不再相关了。您正在根据FindAll返回的列表而不是原始列表进行搜索。
如果将ToList()
操作推迟(或全部删除(到foreach循环,您将看到预期的结果。ToList
将执行与枚举相同的Linq表达式。
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<int> 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 + ", ");