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

Ant*_*tts 88 .net collections list

我已经看到它们以很多相同的方式使用了,我担心如果我不能更好地理解这一点,我将要走上一条不可逆转的设计之路.另外,我正在使用.NET.

Ian*_*oyd 68

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

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

可枚举没有订单.您无法在集中添加或删除项目.你甚至无法获得集合中的项目数.它严格允许您一个接一个地访问集合中的每个项目.

集合是一个可修改的集合.您可以在集合中添加和删除对象,也可以获取集合中的项目数.但是仍然没有订单,因为没有订单:无法按索引访问项目,也没有任何方法可以排序.

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

实际上,在查看这些接口时,它们会相互构建:

  • interface IEnumerable<T>

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

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

    • Insert
    • IndexOf
    • RemoveAt

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

  • IEnumerable的
  • ICollection的
  • IList的

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

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

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

ICollection<User> users = new Collection<User>();
users.Add(new User());
Run Code Online (Sandbox Code Playgroud)

如果您关心排序顺序,并且需要订单正确,那么请使用List:

IList<User> users = FetchUsers(db);
Run Code Online (Sandbox Code Playgroud)

以图表形式:

| 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        |
Run Code Online (Sandbox Code Playgroud)

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

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

所以你可以轻松改变:

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

SaveEveryUser(users);
Run Code Online (Sandbox Code Playgroud)

TL;博士

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

选择您需要的概念,然后使用匹配的类.

  • OP询问了具体类型,并对接口进行了比较.具体类型Collection <T>实现IList <T>并具有索引功能. (8认同)
  • 答案是好的,但偏离了这个问题.不能满足你对Collection <T>和List <T>类的答案,我的意思是从问题的角度来看,如果我试图验证你的观点他们只是不合理.对于一般目的的答案,您可能是正确的,因为集合没有排序,因此没有索引,但是列表是有序的,因此可以在某个索引处插入. (2认同)
  • 如果列表是有序的而集合是无序的,这将是一个巨大的功能差异,可以轻松引导新学习者(如我)进行选择。但是等等,你为什么说一个集合没有顺序?它提供 [IndexOf()](https://msdn.microsoft.com/en-us/library/ms132410(v=vs.110).aspx) 和 [RemoveAt()](https://msdn.microsoft. com/en-us/library/ms132414(v=vs.110).aspx) 方法,所以它是有序的,不是吗?我在这里错过了什么吗? (2认同)

Ada*_*sek 50

Collection<T>是一个可定制的包装器IList<T>.虽然IList<T>没有密封,但它没有提供任何定制点.Collection<T>默认情况下,方法被委托给标准IList<T>方法,但可以轻松覆盖以执行您想要的操作.也可以将事件中的事件连接Collection<T>到我认为不能用IList完成的事件中.

简而言之,在事实之后扩展它会容易得多,这可能意味着更少的重构.

  • @DeeStackOverflow - 因为任何使用不同API的代码都不会使用方法隐藏 - 即任何寻找`IList`,`IList <T>`,`List <T>`等的东西.总之,你没有想是否会被召唤.多态性解决了这个问题. (4认同)

Arn*_*kas 42

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

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

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

以上只是建议.

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


Mar*_*ell 37

List<T>是一个非常常见的容器,因为它非常通用(有许多方便的方法,如Sort,Find等) - 但如果你想覆盖任何行为(例如,检查插入项目),则没有扩展点.

Collection<T>是任何IList<T>(默认为List<T>)的包装- 它有扩展点(virtual方法),但没有那么多的支持方法Find.由于间接性,它略微慢List<T>,但不是很多.

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

  • @tuinstoel - 但添加是微不足道的. (7认同)
  • Collection <T>缺少方法foreach,即使在Linq-to-Objects中也是如此. (6认同)

tui*_*oel 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());


}
Run Code Online (Sandbox Code Playgroud)

在我的机器List<>上几乎快两倍.

编辑

我无法理解为什么人们会贬低这一点.在我的工作机器和家用机器上,List <>代码的速度提高了80%.

  • 列表的类型字母比集合少:) (17认同)
  • List的方法不可继承,因此没有检查它们是否已被继承; Collection的方法是可继承的.优点是您可以使用Collection作为基类继承并创建自定义Collection. (10认同)
  • 在我的机器上尝试它并且列表快了大约20%.会有兴趣讨论为什么会这样.也许列表更好地分配内存. (2认同)

Man*_*anu 11

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


小智 5

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

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