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) {
...
}
谁能解释这种行为?
此代码有效:
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) {
...
}