Linq:选择是否带有ToList()

时间:2019-01-31 13:43:27

标签: c# linq pointers function-pointers

任何人都可以解释这种行为吗?

此代码有效:

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不同。特别是我不明白最后一种情况会发生什么

2 个答案:

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