我已经看到它们以很多相同的方式使用了,我担心如果我不能更好地理解这一点,我即将走上一条不可逆转的设计之路。另外,我正在使用.NET。
答案 0 :(得分:60)
在C#中,有三个概念用于表示一包物体。为了增加功能,它们是:
可枚举没有订单。您无法在集中添加或删除项目。你甚至无法获得集合中的项目数。它严格允许您一个接一个地访问集合中的每个项目。
集合是一个可修改的集合。您可以在集合中添加和删除对象,也可以获取集合中的项目数。但是仍然没有顺序,因为没有顺序:没有办法按索引访问项目,也没有办法排序。
列表是一组有序的对象。您可以对列表进行排序,按索引访问项目,按索引删除项目。
事实上,在查看这些接口时,它们是相互依赖的:
interface IEnumerable<T>
GetEnumeration<T>
interface ICollection<T> : IEnumerable<T>
Add
Remove
Clear
Count
interface IList<T> = ICollection<T>
Insert
IndexOf
RemoveAt
在声明变量或方法参数时,您应该选择使用
基于概念,你需要处理一组对象。
如果您只需要能够对列表中的每个对象执行某些操作,那么您只需要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());
如果您关心排序顺序,并且需要订单正确,请使用列表:
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);
选择您需要的概念,然后使用匹配的类。
答案 1 :(得分:48)
Collection<T>
是IList<T>
周围的可自定义包装器。虽然IList<T>
未密封,但它不提供任何自定义点。 Collection<T>
的方法默认委托给标准IList<T>
方法,但可以轻松覆盖以执行您想要的操作。也可以在Collection<T>
内汇总我认为不能用IList完成的事件。
简而言之,在事实之后扩展它会容易得多,这可能意味着更少的重构。
答案 2 :(得分:42)
List<T>
旨在供应用程序代码内部使用。您应该避免编写接受或返回List<T>
的公共API(请考虑使用超类或集合接口)。
Collection<T>
为自定义集合提供基类(尽管可以直接使用)。
请考虑在代码中使用Collection<T>
,除非您需要List<T>
的特定功能。
以上只是建议。
[改编自:框架设计指南,第二版]
答案 3 :(得分:37)
List<T>
是一个非常常见的容器,因为它非常通用(有许多方便的方法,如Sort
,Find
等) - 但如果你没有扩展点想要覆盖任何行为(例如,检查插入项目)。
Collection<T>
是任何IList<T>
的包装(默认为List<T>
) - 它有扩展点(virtual
方法),但没有像{{Find
那样多的支持方法{1}}。由于间接,它比List<T>
略慢,但不是很多。
使用LINQ,List<T>
中的额外方法变得不那么重要了,因为LINQ-to-Objects无论如何都倾向于提供它们......例如First(pred)
,OrderBy(...)
等。< / p>
答案 4 :(得分: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&lt;&gt;代码快80%。
答案 5 :(得分:11)
List表示项目顺序很重要的集合。它还支持方法s.a.排序和搜索。集合是一种更通用的数据结构,它对数据的假设较少,并且支持较少的操作方法。如果要公开自定义数据结构,则应该扩展该集合。如果您需要操作数据而不暴露数据结构,列表可能是更方便的方法。
答案 6 :(得分:4)
这是研究生的一个问题。 T的集合有点抽象;可能有一个默认实现(我不是.net / c#guy)但是一个集合将具有添加,删除,迭代等基本操作。
T的列表暗示了一些关于这些操作的细节:添加应该花费恒定的时间,删除应该花费时间与元素的数量成比例,getfirst应该是一致的时间。通常,List是一种Collection,但Collection不一定是List。
答案 7 :(得分:4)
Hanselman Speaks:“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命名空间包含可用作可重用库的对象模型中的集合的类。当属性或方法返回集合时使用这些类。”
答案 8 :(得分:4)
所有这些接口都继承自IEnumerable
,您应该确保理解。该接口基本上允许您在foreach语句中使用该类(在C#中)。
ICollection
是您列出的最基本的界面。它是一个可枚举的接口,支持Count
,而且是关于它的。 IList
是ICollection
的所有内容,但它也支持添加和删除项目,按索引检索项目等。它是“对象列表”最常用的界面,这是模糊,我知道。 IQueryable
是一个支持LINQ的可枚举接口。您始终可以从IList创建IQueryable
并使用LINQ to Objects,但您还可以在LINQ to SQL和LINQ to Entities中找到用于延迟执行SQL语句的IQueryable
。 IDictionary
在某种意义上是一种不同的动物,它是唯一键与值的映射。它也是可枚举的,你可以枚举键/值对,但除此之外它与你列出的其他目的不同。答案 9 :(得分:4)
根据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”的“2008年12月29日22:31”帖子声称速度测试显示List(Of T)。添加比收集(Of T)更快。添加我'用Long's和String's复制。根据MSDN的说法,虽然我只比他声称的80%快了〜33%,但它应该是相反的并且是“n”次!!
答案 10 :(得分:3)
两者都实现相同的接口,因此它们的行为方式相同。也许它们在内部以不同的方式实现,但这必须进行测试。
我看到的唯一真正的区别是名称空间以及Collection<T>
标有ComVisibleAttribute(false)
的事实,因此COM代码无法使用它。
答案 11 :(得分:3)
除了其他asnwers之外,我还编写了通用列表和集合功能的快速概述。集合是List的有限子集:
* = present
o = partially present
Property/Method Collection<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() *