我知道当我调用某些方法时,它会开始执行链接到该集合实例的整个LINQ查询。
示例,每次拨打.Count()
时。我想每次拨打.ToList()
时也会这样。
获取ToList()之后,我对该集合执行“复制”,而不是在集合的新实例上没有写任何LINQ查询,Count()将不会执行任何操作。 (右?)
如果我在2个名单上拨打.Union()
怎么办?并且2个不可数?和.Except()
它是一样的吗?
尝试使用一些Trace / Diagnostic,但我无法理解何时执行LINQ查询。
答案 0 :(得分:2)
Union和Except被推迟执行。阅读文档中的备注部分以获取更多信息。
http://msdn.microsoft.com/en-us/library/bb341731
http://msdn.microsoft.com/en-us/library/bb300779
此外,在这种情况下,当您确定发生了什么事情时,您可以使用Reflector或任何其他.NET反编译器。这真的很有帮助。
答案 1 :(得分:1)
您的问题的答案取决于两个选项:
.Union
,.Except
,.Where
,。Select
以及大多数其他linq操作.ToList
,.Count
.ToArray
以及实现数据的所有操作使用这两条规则可以预测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
答案 2 :(得分:0)
Linq查询在具有基础集合但 不是集合时执行。您可以使用ToList()
或ToArray
来实现查询。
每个延期执行的Enumerable
扩展程序首先尝试将IEnumerable<T>
转换为IList<T>
(如果需要索引器,则为fe)或ICollection<T>
(如果需要则为{一个Count
)。如果可以的话,它将使用不需要执行查询的“native”方法,否则它将枚举序列。
在MSDN上搜索tem deferred ,以查看方法是延迟执行还是立即执行。如果您检查源代码(例如,通过ILSpy
),您可以通过查找yield keyword
来检测延迟执行的方法。
Union
和Except
。因此,如果您想要保留该结果,则需要ToList
/ ToArray
。
以下是一个示例,Enumerable.Count
的实现:
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null)
{
return collection.Count;
}
ICollection collection2 = source as ICollection;
if (collection2 != null)
{
return collection2.Count;
}
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
num++;
}
}
return num;