List(T)和Collection(T)有什么区别?


92

我已经看到它们以许多相同的方式使用,而且我担心如果我不了解的话,我将沿着不可逆转的设计道路走下去。另外,我正在使用.NET。

Answers:


50

Collection<T>是一个可定制的包装器IList<T>。虽然IList<T>没有密封,但它不提供任何定制点。Collection<T>的方法默认情况下委派给标准IList<T>方法,但是可以很容易地覆盖它们,以执行所需的操作。还可以将事件绑定到一个Collection<T>我不相信可以使用IList完成的事件中。

简而言之,事后扩展它要容易得多,这可能意味着重构要少得多。


@Marc Gravell,@ Adam Lassek:我们不能对List执行相同的操作,方法是使用公共无效的new InsertItem(...)隐藏InsertItem(...)方法,然后调用base.InsertItem(.. 。) 从内部 ?它仍然不会违反合同。(尽管列表中名称为“ Insert”,但仍然如此)。那么,坚持Collections <T>有什么大不了的呢?
DeeStackOverflow 2011年

4
@DeeStackOverflow -即任何看起来的-因为方法隐藏不会被使用不同API的任何代码中使用IListIList<T>List<T>等等,总之,你不知道它是否会被调用。多态性可以解决此问题。
Marc Gravell

@AdamLassek:您可能想在ObservableCollection<T>示例中添加有关的方法,其中方法被覆盖以通知更改。
Kiran Challa

84

在C#中,存在三个用于表示对象包的概念。为了增加功能,它们是:

  • 可枚举 -无序,不可修改
  • 收藏 -可以添加/删除项目
  • 列表 -允许项目具有顺序(按索引访问和删除)

可枚举没有顺序。您不能从集中添加或删除项目。您甚至无法获得集合中的项目数。它严格允许您一个接一个地访问集合中的每个项目。

集合是可修改的集合。您可以从集合中添加和删除对象,还可以获取集合中的项目数。但是仍然没有顺序,而且因为没有顺序:无法通过索引访问项目,也无法进行排序。

列表是一组有序的对象。您可以对列表进行排序,按索引访问项目,按索引删除项目。

实际上,当查看这些接口时,它们是相互构建的:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

声明变量或方法参数时,应选择使用

  • IEnumerable
  • ICollection
  • 清单

基于概念上,您需要处理对象集。

如果您只需要对列表中的每个对象执行某项操作,则只需要IEnumerable

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

如果用户被保存在一个你不关心List<T>Collection<T>Array<T>或其他任何东西。您只需要IEnumerable<T>界面。

如果您需要能够添加,删除或计算集合中的项目,请使用Collection

ICollection<User> users = new Collection<User>();
users.Add(new User());

如果您关心排序顺序,并且需要正确的顺序,请使用List

IList<User> users = FetchUsers(db);

以图表形式:

| Feature                | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items      | X              | X              | X        |
|                        |                |                |          |
| Adding items           |                | X              | X        |
| Removing items         |                | X              | X        |
| Count of items         |                | X              | X        |
|                        |                |                |          |
| Accessing by index     |                |                | X        |
| Removing by indexx     |                |                | X        |
| Getting index of item  |                |                | X        |

List<T>Collection<T>System.Collections.Generic是实现这些接口两类:但是它们不是唯一的类:

  • ConcurrentBag<T>是一袋有序的物品(IEnumerable<T>
  • LinkedList<T>是一个不允许按索引(ICollection)访问物品的包;但您可以随意添加和删除集合中的项目
  • SynchronizedCollection<T> 在有序集合中,您可以在其中按索引添加/删除项目

因此,您可以轻松更改:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

tl; dr

  • 可枚举 -访问项,无序,不可修改
  • 收藏 -可以修改(添加,删除,计数)
  • 列表 -可以按索引访问

选择所需的概念,然后使用匹配的类。


11
OP询问了具体的类型,并且您已经比较了接口。具体类型Collection <T>实现IList <T>并具有按索引访问的功能。
JJS 2015年

2
答案很好,但与问题背道而驰。无法满足您对Collection <T>和List <T>类的回答,我的意思是说,如果我试图验证您的观点,那么他们只是没有道理。对于一般用途的答案,您可能是正确的,即集合没有排序,因此没有索引,但是列表是有序的,因此可以在某个索引处插入。
凯洛·伦(Kylo Ren)2016年

如果我要具有ICollection <T>的功能并进行求解并找到可能性怎么办?

2
如果列表是有序的,而集合是无序的,那么功能上的巨大差异将很容易引导新学习者(如我)选择。但是,等等,为什么您说收藏没有顺序?它提供IndexOf()RemoveAt()方法,所以它是有序的,不是吗?我在这里想念什么吗?
RayLuo

1
@RayLuo我指的是ICollection<T>IList<T>。不同的具体实现可能会有不同的行为。例如,如果您List<T>通过其IEnumerable<T>界面访问,则无法添加,删除,排序或计算列表中的项目。
伊恩·博伊德

43

List<T>适用于应用程序代码内部使用。您应该避免编写接受或返回的公共API List<T>(考虑使用超类或集合接口)。

Collection<T> 提供自定义集合的基类(尽管可以直接使用)。

Collection<T>除非有以下特定功能,否则请考虑在您的代码中使用List<T>您需要。

以上只是建议。

[改编自:框架设计准则,第二版]


值得注意的是,使用任何类型的可变对象来封装其自身状态的类型都应避免返回此类对象,除非有问题的对象具有在发生突变时通知其所有者的方法,或者返回该对象的方法的名称。对象明确表示它正在返回一个新实例。请注意,例如Dictionary<string, List<string>>返回a List<string>就很好,因为字典的状态仅将列表的身份封装在其中,而不是其内容。
2013年

37

List<T>是一个非常常见的容器,因为它用途广泛(具有许多方便的方法,例如SortFind等),但是如果您要覆盖任何行为(例如,检查插入内容),则没有扩展点。

Collection<T>是围绕任何包装程序IList<T>(默认为List<T>)的包装程序-它具有扩展点(virtual方法),但支持的方法却不如Find。由于是间接的,它比慢一点List<T>,但幅度不大。

随着LINQ,额外的方法List<T>变得不那么重要,因为LINQ到对象往往反正他们提供...例如First(pred)OrderBy(...)等等。


6
即使在Linq-to-Objects中,Collection <T>也缺少foreach方法。
tuinstoel

7
@tuinstoel-但添加起来很简单。
马克·格雷夫

12

列表速度更快。

举个例子

private void button1_Click(object sender, EventArgs e)
{
  Collection<long> c = new Collection<long>();
  Stopwatch s = new Stopwatch();
  s.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    c.Add(i);
  }
  s.Stop();
  MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());

  List<long> l = new List<long>();
  Stopwatch s2 = new Stopwatch();
  s2.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    l.Add(i);
  }
  s2.Stop();
  MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());


}

在我的机器List<>上几乎快一倍。

编辑

我不明白为什么人们对此表示反对。在我的工作机和家用机上,List <>代码都快80%。


1
速度如何?抬头?插入?搬走 搜索?为什么会更快?
Doug T.

17
列表要键入的字母少于集合:)
RedFilter

1
收集方法较少。因此它更快。QED。(开玩笑,我不是在拖钓)

2
在我的机器上试用过,列表速度提高了约20%。对为什么会这样的一些讨论感兴趣。也许列表与分配内存更好。

10
List的方法不可继承,因此不会检查它们是否已被继承;集合的方法是可继承的。好处是您可以将Collection用作基类,以从其继承并创建自定义Collection。
理查德·加兹登2010年

11

列表表示项目顺序很重要的集合。它还支持排序和搜索方法。收集是一种更通用的数据结构,它对数据的假设较少,并且支持的数据处理方法也较少。如果要公开自定义数据结构,则可能应该扩展集合。如果您需要不公开数据结构来处理数据,则列表可能是更方便的方法。


4

这是那些研究生的问题之一。T的集合有点抽象。可能有一个默认的实现(我不是.net / c#家伙),但是集合将具有基本的操作,例如添加,删除,迭代等。

T的列表暗示了有关这些操作的一些细节:加法应该花费固定的时间,移出应该花费与元素数量成比例的时间,getfirst应该是恒定的时间。通常,列表是一种集合,但集合不一定是一种列表。


4

Hanselman说:“ Collection<T>看起来像一个列表,甚至在List<T>内部都有一个列表。每个单一方法都委托给内部List<T>。它包含一个受保护的属性,该属性公开List<T>。”

编辑: Collection<T>System.Generic.Collections .NET 3.5中不存在。如果您从.NET 2.0迁移到3.5,则如果您使用了大量的代码,则需要更改一些代码Collection<T>对象的情况下,除非我遗漏了一些明显的东西...

编辑2:Collection<T>现在位于.NET 3.5的System.Collections.ObjectModel命名空间中。帮助文件说:

“ System.Collections.ObjectModel命名空间包含可在可重用库的对象模型中用作集合的类。当属性或方法返回集合时,请使用这些类。”


4

所有这些接口都继承自IEnumerable,您应该确保您了解这些接口。该接口基本上允许您在foreach语句(在C#中)中使用该类。

  • ICollection是您列出的最基本的接口。这是一个支持a的枚举接口,仅Count此而已。
  • IList是所有ICollection内容,但它还支持添加和删除项目,按索引检索项目等。这是“对象列表”最常用的接口,我知道这很模糊。
  • IQueryable是支持LINQ的可枚举接口。您总是可以IQueryable从IList 创建一个,并使用LINQ to Objects,但是您还会发现IQueryable在LINQ to SQL和LINQ to Entities中用于延迟执行SQL语句的。
  • IDictionary从唯一键到值的映射的意义上讲,它是另一种动物。它也可以枚举,因为您可以枚举键/值对,但除此之外,它的作用与列出的其他目的不同

ICollection支持添加/删除/清除:msdn.microsoft.com/zh-cn/library/…–
失忆症

4

根据MSDN,List(Of T).Add是“ O(n)操作”(超过“容量”时),而Collection(Of T).Add 始终是“ O(1)操作”。如果使用数组实现列表并收集链接列表,那将是可以理解的。但是,如果是这种情况,则可以期望Collection(Of T).Item是“一个O(n)操作”。但是-是- 不是!?!就像List(Of T).Item一样,Collection(Of T).Item是一个“ O(1)操作”。

最重要的是,上面提到的“ tuinstoel”在“ 08年12月29日22:31”上声称速度测试显示List(Of T)。Add要比Collection(Of T)快。 Long和String。根据MSDN的说法,虽然我的速度只比他声称的80%快33%,但这应该是相反的情况,并且是“ n”倍!


3

两者实现相同的接口,因此它们的行为方式相同。也许它们在内部的实现方式有所不同,但这必须进行测试。

我看到的唯一真正的区别是名称空间和Collection<T>带有标记的事实ComVisibleAttribute(false),因此COM代码无法使用它。


它们实现不同的接口-List <T>实现IList <T>,而Collection <T>不实现。
Bevan

@Bevan在c#中尝试,它们都实现了相同的接口集
Kylo Ren

1
这是一个有趣的变化@KyloRen -他们,现在都实现了同一组接口; 早在08年就不是这种情况。
Bevan 2016年

1
@Bevan有趣。不知道两个不同类的原因是什么,一个只有一些额外的方法。
Kylo Ren

3

除了其他解决方案之外,我还对通用列表和收集功能进行了快速概述。集合是列表的有限子集:

* = 存在
o = 部分存在

属性/ 方法集合< T > 列表< T > --------------------------------------- -------      

Add()                *              *
AddRange()                          *
AsReadOnly()                        *
BinarySearch()                      *
Capacity                            *
Clear()              *              *
Contains()           *              *
ConvertAll()                        *
CopyTo()             o              *
Count                *              *
Equals()             *              *
Exists()                            *
Find()                              *
FindAll()                           *
FindIndex()                         *
FindLast()                          *
FindLastIndex()                     *
ForEach()                           *
GetEnumerator()      *              *
GetHashCode()        *              *
GetRange()                          *
GetType()            *              *
IndexOf()            o              *
Insert()             *              *
InsertRange()                       *
Item()               *              *
LastIndexOf()                       *
New()                o              *
ReferenceEquals()    *              *
Remove()             *              *
RemoveAll()                         *
RemoveAt()           *              *
RemoveRange()                       *
Reverse()                           *
Sort()                              *
ToArray()                           *
ToString()           *              *
TrimExcess()                        *
TrueForAll()                        *
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.