出于显而易见的原因,在适用的情况下,我一直首选使用IEnumerable而不是List。在当前项目中,我碰到了IList,在接受了它之后,Internet告诉我,除了一个属性(对进一步过滤的支持)之外,它们之间没有显着差异。
由于我不确定这对于C#中的迭代器意味着什么,因此我也同意这一点。在“支持进一步过滤”的点击数不胜数的点击中,任何可能的相关答案都淹没了,告诉我IEnumerable做到了,而IList却没有。
所以我在这里问两个问题。
由于这是基于许多帖子的一般性观察,因此我无法在此处列出所有内容。一个示例可能是this particular link。
最佳答案
没有“进一步过滤”之类的东西。
过滤集合通常是使用 IEnumerable.Where
扩展方法完成的,该方法是为IEnumerable
接口(interface)定义的。由于IList
继承自IEnumerable
,因此您可以在两个接口(interface)上调用Where
(在Where
上调用IList
实际上会调用 IEnumerable.Where
扩展方法)。因此,在两种情况下,都将调用相同的基本方法,并且结果值的类型将为IEnumerable
(当应用于列表时不是IList
)。这可能是造成混淆的原因(“您不能再过滤IList
了,因为您已经没有了?”),但是没有什么能阻止您再次过滤生成的IEnumerable<T>
,甚至不能编写自己的扩展方法来创建新的List
。每次调用IEnumerable
。
问题中链接到的帖子质量低下,不应该被信任。
有关详细说明,请参见下文。
尽管两种情况下通常都使用IList
扩展方法(即LINQ),但是您可以从两个接口(interface)中过滤元素几乎相同,因为IEnumerable
继承自Where
。在两种情况下,您都可以随意链接许多Where
语句:
// `items` is an `IEnumerable<T>`, so we can call the `Where` extension method.
// Each call creates a new instance, and keeps the previous one unmodified.
IEnumerable<T> items = GetEnumerableItems();
var filteredItems = items
.Where(i => i.Name == "Jane") // returns a new IEnumerable<T>
.Where(i => i.Gender == "Female") // returns a new IEnumerable<T>
.Where(i => i.Age == 30) // returns a new IEnumerable<T>
// `list` is an `IList<T>`, which also inherits from `IEnumerable<T>`.
// Calling `Where` on a list will also not modify the original list.
IList<T> list = GetEnumerableItems();
var filteredList = list
.Where(i => i.Name == "John") // returns a new IEnumerable<T>
.Where(i => i.Gender == "Male") // returns a new IEnumerable<T>
.Where(i => i.Age == 30) // returns a new IEnumerable<T>
.ToList(); // returns a new List<T> (optional)
对该词进行谷歌搜索会返回几篇提及该词的文章(例如this或this),它们似乎都在复制相同的来源,似乎是窃,没有背后的实际理由。我唯一想到的是,将
IEnumerable<T>
应用于IEnumerable<T>
会返回一个新的(过滤后的)Where
,您可以再次对其应用Where
(“进一步”过滤)。但这确实很模糊,因为即使将生成的接口(interface)是IList<T>
,将IEnumerable<T>
应用于List<T>
也不会阻止您对其进行过滤。如评论中所述,值得一提的是,IList<T>
类作为FindAll
的具体实现,公开了 List<T>
方法,该方法返回新的过滤后的具体IList<T>
(并且可以“进一步过滤”),但这不是IEnumerable<T>
的一部分。重复过滤
FindAll
和将列表过滤到新列表(例如,使用List<T>
)之间的主要区别在于,后者需要在每个步骤中创建一个新的IEnumerable<T>
实例,而Where
使用延迟执行并且不会占用额外的内存从为每个Where
调用存储一些微小的状态信息。再说一次,只是为了避免造成混淆,如果您在List<T>
上调用IEnumerable<T>
,您仍然可以获得IList
懒惰的好处。实际差异:
IList<T>
(或实际上是O(1)
,我想您要指的是)表示可以由单独访问的对象的集合。这意味着您可以有效地(在List<T>
时间内)获取某个位置的对象值以及列表的长度。 “不好的事情”是(假设它是在幕后实现的IEnumerable
),这意味着您需要将整个集合保存在内存中。IEnumerable<T>
(即其通用对应的IEnumerable
)可以做的“唯一的事情”是迭代(零个或多个)项目。它没有索引的概念(在没有实际迭代或跳过该项目之前的所有项目的情况下,您无法“跳转”到索引)。而且,在通常情况下,如果没有每次都实际计数项目,您也无法有效地获得长度。另一方面,ojit_code是延迟求值的,这意味着它的元素在即将被求值之前不必存在于内存中。它可以在下面循环访问从磁盘中获取的数十亿行数据,并将其包装在数据库表的下面。它甚至可以是一个无限的集合。关于c# - 迭代器的 "further filtering"是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25302798/