使用什么? 他们如何工作?
我对Enumerators如何工作以及LINQ有一些疑问。 考虑这两个简单的选择:
List<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct().ToList();
要么
IEnumerable<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct();
我改变了我的原始对象的名字,这样看起来就像一个更通用的例子。 查询本身并不重要。 我想问的是这样的:
foreach (Animal animal in sel) { /*do stuff*/ }
我注意到,如果我使用IEnumerable
,当我调试并检查“sel”时(它在IEnumerable中),它有一些有趣的成员:“inner”,“outer”,“innerKeySelector”和“outerKeySelector”似乎是代表。 “内部”成员中没有“Animal”实例,而是“Species”实例,这对我来说很奇怪。 “外层”成员确实包含“动物”实例。 我认为这两位代表决定进入哪些内容?
我注意到如果我使用“Distinct”,“inner”包含6个项目(这是不正确的,因为只有2个是Distinct),但是“outer”包含正确的值。 同样,委托方法可能决定了这一点,但这比我对IEnumerable的了解还多一点。
最重要的是,两种选择中的哪一种选择是最好的表现?
通过.ToList()
邪恶的列表转换?
或者可能直接使用枚举器?
如果可以的话,也请解释一下或者抛出一些解释IEnumerable的使用的链接。
IEnumerable
描述了行为,而List则是该行为的实现。 当你使用IEnumerable
,你给编译器一个延迟工作的机会,直到后来才有可能优化。 如果使用ToList(),则可以强制编译器立即生成结果。
无论何时“堆叠”LINQ表达式,我都使用IEnumerable
,因为通过只指定行为,我给了LINQ一个延迟评估和可能优化程序的机会。 记住LINQ在枚举之前不会生成SQL来查询数据库? 考虑这个:
public IEnumerable<Animals> AllSpotted()
{
return from a in Zoo.Animals
where a.coat.HasSpots == true
select a;
}
public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
return from a in sample
where a.race.Family == "Felidae"
select a;
}
public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
return from a in sample
where a.race.Family == "Canidae"
select a;
}
现在你有一个方法可以选择一个初始样本(“AllSpotted”)和一些过滤器。 所以现在你可以做到这一点:
var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());
那么在IEnumerable
上使用List会更快吗? 仅当您想要阻止多次执行查询时。 但是总体来说更好吗? 那么在上面,Leopards和Hyenas每个都被转换成单个SQL查询,而数据库只返回相关的行。 但是如果我们从AllSpotted()
返回一个List,那么它可能会运行得更慢,因为数据库可能会返回比实际需要更多的数据,并且我们会浪费循环在客户端进行过滤。
在一个程序中,最好延迟将查询转换为列表直到最后,所以如果我要不止一次地通过Leopards和Hyenas枚举,我会这样做:
List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();
实现IEnumerable
的类允许您使用foreach
语法。
基本上它有一种方法来获取集合中的下一个项目。 它不需要整个集合在内存中,也不需要知道其中有多少物品, foreach
只是不断得到下一个物品,直到它耗尽。
在某些情况下,这可能非常有用,例如,在开始处理行之前,您不希望将整个事件复制到内存中的海量数据库表中。
现在List
实现IEnumerable
,但代表了内存中的整个集合。 如果你有一个IEnumerable
并且调用.ToList()
你可以在内存中创建一个枚举内容的新列表。
你的linq表达式返回一个枚举,默认情况下,当你使用foreach
迭代时,表达式会执行。 迭代foreach
时会执行IEnumerable
linq语句,但您可以使用.ToList()
更快地强制迭代。
这就是我的意思:
var things =
from item in BigDatabaseCall()
where ....
select item;
// this will iterate through the entire linq statement:
int count = things.Count();
// this will stop after iterating the first one, but will execute the linq again
bool hasAnyRecs = things.Any();
// this will execute the linq statement *again*
foreach( var thing in things ) ...
// this will copy the results to a list in memory
var list = things.ToList()
// this won't iterate through again, the list knows how many items are in it
int count2 = list.Count();
// this won't execute the linq statement - we have it copied to the list
foreach( var thing in list ) ...
有一篇非常好的文章:Claudio Bernasconi的TechBlog在这里:何时使用IEnumerable,ICollection,IList和List
这里有一些关于场景和功能的基础知识点:
链接地址: http://www.djcxy.com/p/4809.html上一篇: What to Use? How do they work?
下一篇: When to use struct?