IEnumerable vs List - What to Use? How do they work?
我对枚举器的工作方式和LINQ有一些疑问。考虑这两个简单的选择:
1 2 3 4 | List<Animal> sel = (from animal in Animals join race in Species on animal.SpeciesKey equals race.SpeciesKey select animal).Distinct().ToList(); |
或
1 2 3 4 | IEnumerable<Animal> sel = (from animal in Animals join race in Species on animal.SpeciesKey equals race.SpeciesKey select animal).Distinct(); |
我更改了原始对象的名称,使其看起来像一个更通用的示例。查询本身并不那么重要。我想问的是:
1 | foreach (Animal animal in sel) { /*do stuff*/ } |
我注意到,如果我使用
我注意到,如果我使用"distinct","inner"包含6个项目(这是不正确的,因为只有2个项目是不同的),"outer"包含正确的值。同样,可能是委托方法决定了这一点,但这比我对IEnumerable的了解要多一些。
最重要的是,这两个选项中哪一个是性能最佳的?
通过
或者直接使用枚举器?
如果可以的话,请解释一下,或者抛出一些链接来解释IEnumerable的这种用法。
每当我在"stacking"LINQ表达式中使用,只有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; } |
现在你有一个方法,selects初始样品("allspotted"),加上一些滤波器。所以现在你可以这样做:
1 2 | var Leopards = Feline(AllSpotted()); var Hyenas = Canine(AllSpotted()); |
所以它是禁食两
在一个程序,它可能是更好的两个查询Defer转换你的诡计,直到两个极比,所以如果我要枚举的通leopards和hyenas超过一次,这样做的:
1 2 | List<Animals> Leopards = Feline(AllSpotted()).ToList(); List<Animals> Hyenas = Canine(AllSpotted()).ToList(); |
有一条很好的书面市:Claudio贝尔纳斯科尼的techblog这里:当使用IEnumerable,ICollection,IList和战略
这里是一些基础知识点的情景和功能:
实现
基本上,它有一个方法来获取集合中的下一个项。它不需要整个集合在内存中,也不知道其中有多少项,
这在某些情况下非常有用,例如在大型数据库表中,您不希望在开始处理行之前将整个内容复制到内存中。
现在,
Linq表达式返回一个枚举,默认情况下,当使用
我的意思是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 ) ... |
上述关键差一人,ironically回答对一个问题作为一个duplicated封闭它。
IEnumerable is read-only and List is not.
在实际的战略和IEnumerable类型之间的差异
要认识到的最重要的一点是,使用LINQ不会立即对查询进行评估。它只作为迭代生成的
因此,第一个示例通过调用
就性能而言,答案是视情况而定。如果您需要立即评估结果(例如,您正在改变稍后查询的结构,或者如果您不希望
IEnumerable的优点是延迟执行(通常使用数据库)。在实际循环访问数据之前,不会执行查询。这是一个等待到需要时的查询(又称懒惰加载)。
如果您调用tolist,查询将被执行,或者如我所说的"物化"。
两者都有利弊。如果您调用tolist,您可以消除一些关于何时执行查询的秘密。如果你坚持使用IEnumerable,你会得到这样的好处:程序在实际需要之前不会做任何工作。
在将一misused概念股在下跌到那一天。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var names = new List<string> {"mercedes","mazda","bmw","fiat","ferrari"}; var startingWith_M = names.Where(x => x.StartsWith("m")); var startingWith_F = names.Where(x => x.StartsWith("f")); // updating existing list names[0] ="ford"; // Guess what should be printed before continuing print( startingWith_M.ToList() ); print( startingWith_F.ToList() ); |
预期结果
1 2 3 | // I was expecting print( startingWith_M.ToList() ); // mercedes, mazda print( startingWith_F.ToList() ); // fiat, ferrari |
实际结果
1 2 3 | // what printed actualy print( startingWith_M.ToList() ); // mazda print( startingWith_F.ToList() ); // ford, fiat, ferrari |
解释
根据对方的回答,评价结果是deferred
所以我重写的代码在本案例为:
1 2 3 4 5 6 7 8 9 10 11 12 | var names = new List<string> {"mercedes","mazda","bmw","fiat","ferrari"}; // updating existing list names[0] ="ford"; // before calling ToList directly var startingWith_M = names.Where(x => x.StartsWith("m")); var startingWith_F = names.Where(x => x.StartsWith("f")); print( startingWith_M.ToList() ); print( startingWith_F.ToList() ); |
arround播放
http:/ / / / 0 repl.it e8ki
如果您只想枚举它们,请使用
不过,要注意,更改正在枚举的原始集合是一个危险的操作——在本例中,您将首先希望
在添加发布以上所有的答案,这里是我的两美分。有许多其他的比其他类型的列表,这样ICollection implements IEnumerable,ArrayList等。所以,如果我们有任何IEnumerable作为参数的方法,我们可以通过任何类型的采集功能。即,我们可以有两种操作方法对abstraction没有任何具体实施。
有很多的案例(如一个无限狡猾或狡诈的甚大)在两个IEnumerable不能转变的战略。最明显的例子是全素数,全是用他们的Facebook用户的资料,或所有的项目在eBay上。
"不同的是,"狡猾"的对象是"对仓库在这里和现在"尽头",IEnumerable对象的"工作"(只是一小时"。所以,如果我想通过所有的项目在eBay上,一个一个小时会是什么的一点小的计算机可以处理,但.tolist()"将康医药跑了我的记忆,不管是大我的电脑技能。没有电脑我市和行动本身包含这样一种巨大的金额数据。