首页 > 解决方案 > Linq:选择有和没有 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*/

选择函数似乎返回一个新IEnumerable的,在这两种情况下,在调试之前fullPathTabAssociation.Clear(),值都是正确的newValues并且不同于fullPathTabAssociation. 特别是我不明白最后一种情况会发生什么

标签: c#linqpointersfunction-pointers

解决方案


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

推荐阅读