我对Enumerators和LINQ的工作方式有疑问。 考虑以下两个简单选择:
List sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct().ToList();
要么
IEnumerable 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”,这最后两个似乎是代表。 “内部”成员中没有“动物”实例,而是“物种”实例,这对我来说很奇怪。 “外部”成员确实包含“动物”实例。 我假设这两个代表确定哪个进出什么?
我注意到,如果我使用“ Distinct”,则“ inner”包含6个项目(这是不正确的,因为只有2个是Distinct),但是“ outer”确实包含正确的值。 同样,可能委托方法确定了这一点,但这比我对IEnumerable的了解还多。
最重要的是,这两个选项中哪个是性能最佳的?
通过.ToList()邪恶列表转换?
还是直接使用枚举器?
如果可以的话,也请解释一下或抛出一些链接来解释IEnumerable的用法。
#1楼
没有人提到一个关键的差异,具有讽刺意味的是,作为一个重复的问题,有人回答了一个封闭的问题。
IEnumerable是只读的,而List不是。
#2楼
有一篇非常不错的文章由:Claudio Bernasconi的TechBlog撰写: 何时使用IEnumerable,ICollection,IList和List
这里是有关方案和功能的一些基本知识:
#3楼
要实现的最重要的事情是,使用Linq,查询不会立即得到评估。 它仅作为在foreach中迭代生成的IEnumerable一部分而运行-这就是所有奇怪的委托正在做的事情。
因此,第一个示例通过调用ToList并将查询结果放入列表中来立即评估查询。
第二个示例返回一个IEnumerable ,其中包含稍后运行查询所需的所有信息。
就性能而言,答案取决于它 。 如果您需要一次评估结果(例如,您要对稍后查询的结构进行变异,或者您不希望IEnumerable上的迭代花费很长时间),请使用列表。 否则使用IEnumerable 。 默认情况下,应该在第二个示例中使用按需评估,因为通常会使用较少的内存,除非有特殊原因将结果存储在列表中。
#4楼
如果您只想枚举它们,请使用IEnumerable 。
但是请注意,更改要枚举的原始集合是一项危险的操作-在这种情况下,您将需要首先ToList 。 这将为内存中的每个元素创建一个新的list元素,枚举IEnumerable ,因此如果仅枚举一次,则性能会降低-但更安全,有时List方法很方便(例如,在随机访问中)。
#5楼
IEnumerable的优点是延迟执行(通常使用数据库)。 在您实际遍历数据之前,查询将不会执行。 这是一个查询,直到需要它为止(又称延迟加载)。
如果您调用ToList,查询将被执行,或者像我想说的那样“物化”。
两者都有优点和缺点。 如果调用ToList,则可以消除执行查询时的神秘性。 如果坚持使用IEnumerable,您将获得以下优势:该程序在实际需要之前不会执行任何工作。