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

我已经看到他们用了很多相同的方式,而且我担心如果我不能更好地理解这一点,我即将走上一条不可逆转的devise道路。 另外,我正在使用.NET。

Collection<T>是一个可定制的IList<T>包装器。 虽然IList<T>没有密封,但没有提供任何定制点。 Collection<T>的方法默认是委托给标准的IList<T>方法,但是可以很容易地被覆盖来做你想做的事情。 也可以在Collection<T>内连接事件,我不相信可以用IList来完成。

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

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

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

考虑在你的代码中使用Collection<T> ,除非有你需要的List<T>特定function。

以上只是build议。

[改编自:框架devise指南,第二版]

在C#中,有三个用于表示一个对象的概念。 为了增加function,他们是:

  • 可枚举 – 无序,不可修改
  • collections – 可以添加/删除项目
  • 列表 – 允许项目有订单(通过索引访问和删除)

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

集合是一个可修改的集合。 您可以添加和删除集合中的对象,也可以获取集合中的项目的数量。 但还是没有秩序,因为没有秩序:没有办法通过索引来访问一个项目,也没有任何sorting的方法。

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

事实上,当为这些界面查看时,他们彼此依靠:

  • interface IEnumerable<T>

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

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

    • Insert
    • IndexOf
    • RemoveAt

在声明variables或方法参数时,应该select使用

  • IEnumerable的
  • ICollection的
  • IList的

基于概念上你需要做的一组对象。

如果您只需要能够对列表中的每个对象执行某些操作,那么您只需要IEnumerable

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

你不关心用户是否保存在一个List<T>Collection<T>Array<T>或其他的东西里。 您只需要IEnumerable<T>接口。

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

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

如果您关心sorting顺序,并且需要该顺序是正确的,则使用列表

 IList<User> users = FetchUsers(db); 

以图表forms:

 | 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 | 

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

  • ConcurrentBag<T>是一个有序的对象包( IEnumerable<T>
  • LinkedList<T>是一个不允许通过索引( ICollection )访问项目的包。 但你可以任意添加和删除集合中的项目
  • SynchronizedCollection<T>在有序集合中,您可以在其中按索引添加/删除项目

所以你可以很容易地改变:

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

TL;博士

  • 可枚举 – 访问项目,无序,不可修改
  • 集合 – 可以修改(添加,删除,计数)
  • 列表 – 可以通过索引访问

select你需要的概念 ,然后使用匹配的类。

List<T>是一个非常常见的容器,因为它非常多才多艺(有很多方便的方法,如SortFind等),但是如果你想覆盖任何行为(没有扩展点) , 例如)。

Collection<T>是任何IList<T> (默认为List<T> )的包装 – 它具有扩展点( virtual方法),但没有像Find那样多的支持方法。 由于间接性,它比List<T>稍慢,但不是太多。

使用LINQ, List<T>的额外方法变得不那么重要,因为LINQ-to-Objects倾向于提供它们…例如First(pred)OrderBy(...)

列表代表项目顺序很重要的集合。 它也支持方法sasorting和search。 集合是一个更通用的数据结构,对数据的假设较less,也支持更less的方法来操纵它。 如果你想公开自定义数据结构,你应该扩展集合。 如果您需要操作不公开数据结构的数据,列表可能是更方便的方法。

列表更快。

做例如

 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%。

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

T列表隐含了一些关于这些操作的细节:添加应该采取一定的时间,删除应该花费与元素数量成正比的时间,首先应该是consant时间。 一般来说,一个List是一种Collection,但一个Collection不一定是一种List。

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命名空间包含可在可重用库的对象模型中用作集合的类。当属性或方法返回集合时,请使用这些类。

所有这些接口inheritanceIEnumerable ,你应该确保你明白。 该接口基本上可以让你在foreach语句中使用该类(在C#中)。

  • ICollection是您列出的接口中最基本的。 这是一个支持Count的枚举接口,就是这个。
  • IListICollection一切,但它也支持添加和删除项目,通过索引检索项目等。这是“对象列表”最常用的接口,这是我知道的模糊。
  • IQueryable是一个支持LINQ的枚举接口。 您总是可以从IList创build一个IQueryable并使用LINQ to Objects,但是您也会发现IQueryable用于延迟执行LINQ to SQL和LINQ to Entities中的SQL语句。
  • IDictionary是一种不同的动物,它是唯一键值映射。 这也是可枚举的,你可以枚举键/值对,但除此之外,它的作用与您列出的其他目的不同

根据MSDN,List(Of T).Add是“一个O(n)操作”(当超过“容量”时),而Collection(Of T).Add 总是 “一个O(1)操作”。 这是可以理解的,如果List使用数组和集合链接列表实现。 但是,如果是这样的话,人们会认为Collection(Of T).Item是“一个O(n)操作”。 但是 – 不是 ! Collection(Of T).Item是“O(1)操作”,就像List(Of T).Item一样。

最重要的是,“tuinstoel”的“08年12月29日在22:31”上面声称速度testing显示List(Of T).Add比集合(Of T)快.Add我已经转载龙的和弦的。 虽然我只比自己的80%快了33%,根据MSDN,它应该是相反的,“n”倍!

两者都实现相同的接口,所以他们会performance相同的方式。 也许他们在内部的实施方式不同,但这必须经过testing。

我看到的唯一真正的区别是命名空间和Collection<T>ComVisibleAttribute(false)标记的事实,所以COM代码不能使用它。

除了其他asnwers,我已经编译了通用列表和收集function的快速概述。 集合是列表的有限子集:

 * =现在
 o =部分存在

属性/方法集合<T> List <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() *