C#中的各种集合通用接口之间的区别


11

我已经从事Windows的C#和ASP.net MVC开发工作了一段时间。但是我在一些方面仍然不清楚。我试图了解使用和互换相似种类的通用集合接口之间的基本区别和性能问题。

之间有什么根本区别IEnumerable<T>ICollection<T>List<T>(Class)

我似乎在使用和交换它们时在我的应用程序中没有发现任何问题。另外,还有其他类似的通用集合可以与这三个集合互换吗?


2
还存在的IList <T>以及
JK。

Answers:


19

List <T>是一个类,并且实现ICollection <T>IEnumerable <T>接口。同样,ICollection <T>扩展了IEnumerable <T>接口。它们是不可互换的,至少从所有角度来看都是不可互换的。

如果您具有List <T>,则可以确保此对象实现ICollection <T>和IEnumerable <T>接口需要实现的方法和属性。编译器知道它,并且可以将它们“隐式”转换为ICollection <T>或IEnumerable <T>隐式。但是,如果您有ICollection <T>,则必须先在代码中显式检查它是否是List <T>或其他内容,也许是Dictionary <T>(其中T是KeyValuePair),然后再将其强制转换为您的内容欲望。

您知道ICollection扩展了IEnumerable,因此您可以将其转换为IEnumerable。但是,如果只有IEnumerable,则不能保证它是列表。可能是,但是可能是其他。例如,如果您确实尝试将List <T>强制转换为Dictionary <T>,则应该期待一个无效的强制转换异常。

因此它们不是“可互换的”。

另外,还有很多通用接口,请查看在System.Collections.Generic命名空间中可以找到的内容。

编辑:关于您的评论,如果您使用List <T>或它实现的接口之一,则绝对不会降低性能。您仍然需要创建一个新对象,签出以下代码:

List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;

listmyCollmyEnum都指向同一对象。无论您将其声明为列表,ICollection还是IEnumerable,我仍然需要程序创建列表。我可以这样写:

ICollection<T> myColl = new List<T>();

MYCOLL在运行时仍然是一个列表。

但是,这是最重要的一点…… 为了减少耦合并提高可维护性,您应该始终使用对您来说尽可能最小的分母来声明变量和方法参数,无论是接口,抽象类还是具体类。

想象一下,“ PerformOperation”方法唯一需要的是枚举元素,进行一些工作并退出,在这种情况下,您不需要List <T>中可用的一百种方法,只需要IEnumerable <T中可用的方法即可。 >,因此以下情况适用:

public void PerformOperation(IEnumerable<T> myEnumeration) { ... }

这样,您和其他开发人员便知道可以将实现IEnumerable <T>接口的类的任何对象赋予该方法。它可能是列表,字典或其他开发人员编写的自定义集合类。

相反,如果您明确指定需要一个具体的List <T>(尽管在现实生活中很少见,但仍然可能发生),那么您和其他开发人员都知道它必须是List或另一个继承的具体类来自列表。


首先谢谢。现在,关注点是如何决定使用??。由于List <T>实现了两个接口,为什么不总是在需要IEnumerable或ICollection的每个地方使用它。始终使用列表会对性能产生影响吗?请编辑您的答案以回答这些问题
Pankaj Upadhyay

我经过编辑以回答您的表现问题
Jalayn

+1,但我要补充一点,在极少数情况下,您实际上需要将列表传递给方法,应该使用IList而不是List在方法声明中使用。
Konamiman

@Konamiman-取决于您是否需要List<>特定的功能,例如.AddRange()。在IList<>不公开这一点。
Bobson

6

看看ICollectionIEnumerable的MSDN页面。

用非常抽象的术语来说,这就是我对这些类型的构想。

IEnumerable是可以枚举的任何东西-即,迭代。它不一定意味着“集合”;例如,一个IQueryable实现IEnumerable,它不是一个集合,而是可以查询返回对象的东西。要实现IEnumerable,只需要在查询对象时就可以返回对象。我可能会说我有今天要执行的无数任务(它不是清单,因为我没有写下来或拟定它,但是我可以告诉你我现在要做什么,并且如果您问“然后呢?”,我可以告诉您以下任务)。

ICollection比IEnumerable更具体。一个关键的区别是,一个集合知道它包含多少个项目。要计算一个Enumerable中有多少个项目,您可以有效地遍历并计数:

我:伙计们,你们每个人都有几件物品?

不可思议:我真的不知道。好吧,这是一件。我还有一个,所以是两个。还有一个,所以是三个...另一个是...好,所以是2382。没有其他项目了,所以我有了2382。不要再问我,因为我将不得不再次检查它们。

收藏品:我有2382件物品。我已经知道了

集合通常是一种已经知道所有元素在哪里的东西,并且在您要寻找它们时不必去寻找或生成它们。它比枚举更具体。

在我看来,Enumerable和Collection之间的差异远大于Collection和List之间的差异。实际上,我在努力考虑Collection和List之间的实际区别,但是我相信List提供了更好的搜索和排序方法。

其他类型的Collection包括QueueStack,以及Dictionary

这些类型的名称非常有用-您可以将队列和堆栈视为它们在现实世界中的对应对象,并考虑与List之间可能存在的差异。


“我正在努力考虑馆藏和清单之间的实际区别”。……稍后,您将自己回答。一个List是一个ICollection,而是一个ICollection并不总是一个ListQueueStackDictionary,...)
史蒂芬Jeuris

@Steven这是一个非常漫不经心的答案。我同意这是一个重要的区别,但我不会称之为实际区别。对用户意味着什么?
Kirk Broadhurst,

这很容易!:) Queue<int> queue = (Queue<int>)list;InvalidCastExceptionlist不为时抛出一个Queue<int>。队列和列表之间的差异超出了此问题的范围。
史蒂芬·杰里斯

IEnumerable能否返回当前项和一项不是关键的方面-您暗示了这一点,但请不要明确地说。本质上,仅实现IEnumerable的某些东西在查询时不能返回其成员的任意项-仅当前项和下一项。
cori 2011年

@cori这是一种非常简洁的表达方式,比我的回答清楚得多。
柯克·布罗德赫斯特

-1

可查询的:

直到真正遍历项目才执行查询,可能是通过执行.ToList()

IEnumerable:

前向项目列表。不通过项目0-3,您将无法获得“项目4”。只读列表,您不能添加或删除列表。仍可能使用延迟执行。

IList:

随机访问完全在内存中的完整列表,支持添加和删除

ICollection:

在IEnumerable和IList之间。什么是“最佳”取决于您的要求。通常,如果只想显示项目,则IEnumerable就足够了。至少总是使用通用变量。


这个答案似乎并没有为先前的答案中已发布的内容添加任何有价值的内容
gna 2013年

这只是一个简单的概念
Zia Qammar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.