任何人都可以解释这种行为吗?
此代码有效:
Dictionary<string, int> fullPathTabAssociation = new Dictionary<string, int>();
//bla bla..
//here fullPathTabAssociation is populated
////bla bla..
var newValues = fullPathTabAssociation
.Where(x => x.Value > index)
.Select(x => new KeyValuePair<string, int>(x.Key, x.Value - 1))
.ToList();
fullPathTabAssociation.Clear();
/*now newValues is populated with correct values*/
此代码无效
Dictionary<string, int> fullPathTabAssociation = new Dictionary<string, int>();
//bla bla..
//here fullPathTabAssociation is populated
////bla bla..
var newValues = fullPathTabAssociation
.Where(x => x.Value > index)
.Select(x => new KeyValuePair<string, int>(x.Key, x.Value - 1))
fullPathTabAssociation.Clear();
/*now newValues is empty*/
select函数似乎返回了一个新的IEnumerable
,在这两种情况下,调试都在fullPathTabAssociation.Clear()
之前进行,这两个值对于newValues
是正确的,并且与fullPathTabAssociation
不同。特别是我不明白最后一种情况会发生什么
答案 0 :(得分:2)
区别在于,通过使用ToList
您正在执行Linq查询并创建新列表。此新创建的列表的内容与fullPathTabAssociation
无关。
在第二个示例中,您仅将查询存储在newValues
中。该查询尚未执行,仅在清除查询源之后才会执行。因此,查询结果为空。
答案 1 :(得分:1)
Linq很懒;它会尽可能推迟工作(最多foreach
或某种物化)。
在第一个摘录中,您使用.ToList()
来实现查询,此处Linq必须执行并提供List<T>
集合:
var newValues = fullPathTabAssociation
.Where(x => x.Value > index)
.Select(x => new KeyValuePair<string, int>(x.Key, x.Value - 1))
.ToList(); // <- Materizataion an actual List<T> required; Linq executes
// Since we have newValues collection (not query) it doesn't depend on аullPathTabAssociation
fullPathTabAssociation.Clear();
在第二个摘录的Linq中,不必做任何事情:
// Just a query, no materialization
var newValues = fullPathTabAssociation
.Where(x => x.Value > index)
.Select(x => new KeyValuePair<string, int>(x.Key, x.Value - 1));
fullPathTabAssociation.Clear();
...
// Only here (on foreach or materialization) Linq has to execute the query;
// and it takes fullPathTabAssociation (which is empty)
foreach (var item in newValues) {
...
}