Linq:Select 有和没有 ToList()

Linq: Select with and without ToList()

谁能解释这种行为?

此代码有效:

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 函数似乎 return 一个新的 IEnumerable,在 fullPathTabAssociation.Clear() 之前进行调试在这两种情况下 newValues 的值都是正确的并且是不同于 fullPathTabAssociation。特别是我不明白最后一个案例发生了什么

不同之处在于,通过使用 ToList,您正在执行 Linq 查询并创建新列表。这个新创建的列表的内容独立于fullPathTabAssociation

在第二个示例中,您仅将查询存储在 newValues 中。该查询尚未执行,只有在清除查询源后才会执行。因此,查询结果为空。

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) {
  ...
}