Answers:
Collection<T>
是一个可定制的包装器IList<T>
。虽然IList<T>
没有密封,但它不提供任何定制点。Collection<T>
的方法默认情况下委派给标准IList<T>
方法,但是可以很容易地覆盖它们,以执行所需的操作。还可以将事件绑定到一个Collection<T>
我不相信可以使用IList完成的事件中。
简而言之,事后扩展它要容易得多,这可能意味着重构要少得多。
IList
,IList<T>
,List<T>
等等,总之,你不知道它是否会被调用。多态性可以解决此问题。
ObservableCollection<T>
示例中添加有关的方法,其中方法被覆盖以通知更改。
在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>
界面。
如果您需要能够添加,删除或计算集合中的项目,请使用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);
选择所需的概念,然后使用匹配的类。
ICollection<T>
和IList<T>
。不同的具体实现可能会有不同的行为。例如,如果您List<T>
通过其IEnumerable<T>
界面访问,则无法添加,删除,排序或计算列表中的项目。
List<T>
适用于应用程序代码内部使用。您应该避免编写接受或返回的公共API List<T>
(考虑使用超类或集合接口)。
Collection<T>
提供自定义集合的基类(尽管可以直接使用)。
Collection<T>
除非有以下特定功能,否则请考虑在您的代码中使用List<T>
您需要。
以上只是建议。
[改编自:框架设计准则,第二版]
Dictionary<string, List<string>>
返回a List<string>
就很好,因为字典的状态仅将列表的身份封装在其中,而不是其内容。
List<T>
是一个非常常见的容器,因为它用途广泛(具有许多方便的方法,例如Sort
,Find
等),但是如果您要覆盖任何行为(例如,检查插入内容),则没有扩展点。
Collection<T>
是围绕任何包装程序IList<T>
(默认为List<T>
)的包装程序-它具有扩展点(virtual
方法),但支持的方法却不如Find
。由于是间接的,它比慢一点List<T>
,但幅度不大。
随着LINQ,额外的方法List<T>
变得不那么重要,因为LINQ到对象往往反正他们提供...例如First(pred)
,OrderBy(...)
等等。
列表速度更快。
举个例子
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%。
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命名空间包含可在可重用库的对象模型中用作集合的类。当属性或方法返回集合时,请使用这些类。”
所有这些接口都继承自IEnumerable
,您应该确保您了解这些接口。该接口基本上允许您在foreach语句(在C#中)中使用该类。
ICollection
是您列出的最基本的接口。这是一个支持a的枚举接口,仅Count
此而已。IList
是所有ICollection
内容,但它还支持添加和删除项目,按索引检索项目等。这是“对象列表”最常用的接口,我知道这很模糊。IQueryable
是支持LINQ的可枚举接口。您总是可以IQueryable
从IList 创建一个,并使用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)操作”。如果使用数组实现列表并收集链接列表,那将是可以理解的。但是,如果是这种情况,则可以期望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”倍!
两者实现相同的接口,因此它们的行为方式相同。也许它们在内部的实现方式有所不同,但这必须进行测试。
我看到的唯一真正的区别是名称空间和Collection<T>
带有标记的事实ComVisibleAttribute(false)
,因此COM代码无法使用它。
除了其他解决方案之外,我还对通用列表和收集功能进行了快速概述。集合是列表的有限子集:
* = 存在
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() *