IList vs IEnumerable:当它们;执行;LINQ查询?
我知道,当我调用一些方法时,它开始执行链接到集合实例的整个LINQ查询 例如,每次我调用IList vs IEnumerable:当它们;执行;LINQ查询?,linq,Linq,我知道,当我调用一些方法时,它开始执行链接到集合实例的整个LINQ查询 例如,每次我调用.Count()。我想每次我调用.ToList()时 在获得ToList()之后,我对该集合进行“复制”,如果我不对该集合的新实例编写任何LINQ查询,Count()将不会执行任何操作。(对吗?) 如果我调用列表2中的.Union(),会怎么样?而在2-Ienumerable上呢?与.Except()相同吗 尝试了一些跟踪/诊断,但我无法真正理解何时执行LINQ查询。延迟执行Union和Except。有关更多
.Count()
。我想每次我调用.ToList()
时
在获得ToList()之后,我对该集合进行“复制”,如果我不对该集合的新实例编写任何LINQ查询,Count()将不会执行任何操作。(对吗?)
如果我调用列表2中的.Union()
,会怎么样?而在2-Ienumerable上呢?与.Except()
相同吗
尝试了一些跟踪/诊断,但我无法真正理解何时执行LINQ查询。延迟执行Union和Except。有关更多信息,请阅读文档中的备注部分
此外,在这种情况下,当您确定引擎盖下发生了什么时,您可以使用Reflector或任何其他.NET反编译器。这真的很有帮助。当Linq查询有一个底层集合,但不是集合时,就会执行该查询。例如,您可以使用
ToList()
或ToArray
对查询进行材质化
每个延迟执行的Enumerable
扩展首先尝试将IEnumerable
强制转换为IList
(如果需要索引器)或ICollection
(如果需要计数)。如果可以,它将使用不需要执行查询的“本机”方法,否则它将枚举序列
搜索延迟打开的tem,查看方法是延迟执行还是立即执行。如果您检查源代码(例如,通过ILSpy
),您可以通过查找来检测延迟执行的方法
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;
ICollection collection=源作为ICollection;
if(集合!=null)
{
返回集合。计数;
}
ICollection collection2=源作为ICollection;
if(collection2!=null)
{
返回集合2.计数;
}
int num=0;
使用(IEnumerator enumerator=source.GetEnumerator())
{
while(枚举数.MoveNext())
{
num++;
}
}
返回num;
问题的答案取决于两个选项:
- 操作类型:懒惰(或延迟)和贪婪。延迟操作不会立即执行,直到代码开始从linq源具体化数据时才会执行。贪婪操作总是立即执行。
- 惰性操作的示例:
.Union
,。除了
,。其中
,.选择
和大多数其他linq操作
- 贪婪的有:
.ToList
、.Count
.ToArray
和所有具体化数据的操作
- 用于linq操作的数据源。当您使用Linq存储时,所有操作(包括懒惰和贪婪)都将立即执行。通常,Linq到外部数据源只会在具体化期间执行延迟操作
使用这两条规则,您可以预测linq的行为:
.Count
和.ToList
将立即执行并具体化数据
在.ToList
之后,您将在内存中获取集合,并且将立即执行以下所有操作(.Count
将再次执行一个操作)
.Union
和.Except
如何表现为懒惰或贪婪取决于数据源的类型。对于内存,他们将是贪婪的,对于SQL则是懒惰的
例如。我有一个可枚举的和延迟的。其中
和。使用贪婪在具体化前后对其选择
操作。计数
或。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;
}
}
在这种情况下,使用reflector或其他反编译器工具来确保“Linq查询是在查询而不是集合时执行的”这句话毫无意义。所以每次我使用贪婪操作时,它都会执行附加到集合的所有查询?这就是我想知道的…我的意思是:我有一个IEnumerable,我对它做了4个查询。如果我执行Count(),我将执行这4个查询。然后,如果我再次执行Count(),我将重新执行这4个查询。但是如果我把IEnumerable变成一个列表,如果我计算()2次,会发生什么?再次执行查询2次?是的,linq构建了惰性命令的表达式树(在适当的数据源上),并在到达贪婪命令时执行整个树。查看其工作原理的简单实用方法是附加到SQL server的日志,并在Debugger或linqpad中逐个添加惰性命令。或者看第9频道:(LINQ Beyond Queries)[和(LINQ技巧和优化)[Scott Allen;)首先,你能指定LINQ-2-what吗?你说的是内存还是非内存?是的,我使用LINQ从SQL管理我的对象(在内存中)
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