对您的问题的回答取决于两个选项:
- 操作类型:懒惰(或延迟)和贪婪。延迟操作不会立即执行,而是延迟到代码开始从您的 linq 源实现数据。贪婪操作总是立即执行。
- 惰性操作示例:
.Union, .Except, .Where, . Select和大多数其他 linq 操作
- 贪心的是:
.ToList,.Count .ToArray以及所有实现数据的操作
- linq 操作的数据源。当您使用 Linq to Memory 时,所有操作(懒惰和贪婪)都将立即执行。通常 Linq到外部数据源只会在物化期间执行惰性操作。
使用这两个规则,您可以预测 linq 的行为方式:
.Count并将.ToList立即执行并实现数据
- 之后
.ToList,您将在内存中收集,并且将立即执行所有后续操作(.Count将再次执行)
.Union懒惰或贪婪的行为方式.Except取决于数据源的类型。对于内存,他们将是贪婪的,对于 SQL 是懒惰的。
LinqPad的示例。在使用贪婪或实现之前和之后,我有一个Enumerable懒惰或延迟.Where和操作:.Select.Count.ToList
void Main()
{
"get enumerable".Dump();
var samplesEnumerable = GetSamples();
"get count on enumerable #1".Dump();
samplesEnumerable.Count().Dump();
"get enumerable to list #1".Dump();
var list = samplesEnumerable.ToList();
"get count on list #1".Dump();
list.Count().Dump();
"get count on list again #2".Dump();
list.Count().Dump();
"get where/select enumerable #1".Dump();
samplesEnumerable
.Where(sample => { sample.Dump(); return sample.Contains("5"); })
.Select(sample => { sample.Dump(); return sample; })
.Dump();
"get where/select list #1".Dump();
list
.Where(sample => { sample.Dump(); return sample.Contains("5"); })
.Select(sample => { sample.Dump(); return sample; })
.Dump();
}
string[] samples = new [] { "data1", "data2", "data3", "data4", "data5" };
IEnumerable<string> GetSamples()
{
foreach(var sample in samples)
{
sample.Dump();
yield return sample;
}
}
样本输出。关键点
在未具体化的数据上,每一次都在一次.Count又一次.List地检索数据
get count on enumerable #1
get where/select enumerable #1
物化数据后,将不再检索可枚举
get enumerable to list #1
get count on list #1
get count on list again #2
get where/select list #1
输出:
get enumerable
get count on enumerable #1
data1
data2
data3
data4
data5
5
get enumerable to list #1
data1
data2
data3
data4
data5
get count on list #1
5
get count on list again #2
5
get where/select enumerable #1
data1
data1
data2
data2
data3
data3
data4
data4
data5
data5
data5
data5
get where/select list #1
data1
data2
data3
data4
data5
data5
data5