思考并回答以下问题:
本章涵盖:
tE14章讨论了标准查询操作符,它们是由IEnumerableT>提供的一套扩展方法,宋适合所有集合。但是,这并不能使所有集合都适合所有任务。我们仍然需要不同的集合类型。有的集合适合根据键来搜索,有的则适合根据位置来访问。有的集合具有“先入先出”的队列行为,有的则更像“先入后出”的栈。还有一些根本没有顺序。
NET Framework针对多种不同的使用场合定义了一系列集合。本章将介绍部分集合类型及其实现的接口。本章还介绍了如何创建自定义集合来支持标准集合功能(比如索引)。除此之外,本章还讨论了如何用yield return语句创建类和方法来实现IEnumerablecT>。利用这个C#2.0引入的特性,可以简单地实现能由foreach语句遍历的集合。
NET Framework中有许多非泛型集合类和接口,但它们主要是为了向后兼容。泛型集合类不仅更快(因为避免了装箱开销) ,还更加类型安全。所以,新代码应该总是使用泛型集合类。本书假定你主要使用泛型集合类型。
更多集合接口
前面讨论了集合如何实现IEnumerablecT>,这是实现集合元素遍历功能的主要接口。更复杂的集合实现了其他许多接口。图16-1展示了集合类实现的接口的层次结构。
这些接口提供了一种标准的方式来执行常规任务,包括遍历、索引和计数。本节将讨论这些接口(至少所有泛型版本),先从图16-1底部的接口开始,然后逐渐上移。
IList IDictionary
可将英语字典看成是一个定义集合;查找“键” (被定义的单词) )即可快速找到定义。类似地,字典集合类是值的集合;每个值都可通过关联的、唯一的键来快速访问。但要注意,英语字典一般按照“键”的字母顺序存储定义。字典类也可选择这样,但一般都没有。最好将字典集合看成是键及其关联值的无序列表,除非文档专门指定了排序方式。类似地,一般不说查找”字典的第6个定义” ;字典类一般只按照键进行索引,而不按位置索引。
列表则相反,它按特定顺序存储值并按位置访问它们。从某种意义上说,列表是字典的一个特例,其中“键”总是一个整数, “键集”总是从0开始的非负整数的一个连续集合。但是,由于两者存在重大差异,所以有必要用一个完全不同的类来表示列表。
所以,选择集合类来解决数据存储或者数据获取问题时,首先要考虑的两个接口就是IList
实现这两个接口的类都必须提供索引器。对于1List
ICollection
IList
Count属性返回集合中的元素总数。从表面来看,只需要用一个for循环就可以遍历集合的每个元素。但是,要真正做到这一点,集合还必须支持按索引来获取(检索)值,而这个功能是ICollection
CopyTo()方法允许将集合转换成数组。该方法包含一个index参数,允许指定在目标数组的什么位置插入元素。注意,要使用这个方法,必须初始化目标数组并使其具有足够大的容量:从index开始,一直到能装下1collection(T)中的所有元素。
主要集合类
共有5类关键的集合类,它们的区别在于数据的插入、存储以及获取的方式。所有泛型类都位于System. Collections .Generic命名空间,等价的非泛型版本位于System.collections命名空间。
列表集合: List
List
这种类称为列表集合,其独特功能是每个元素都可根据索引来单独访问,这和数组一样。因此,可以使用索引器来设置和访问列表集合类中的元素,索引参数值对应于元素在集合中的位置。代码清单16-1展示了一个例子,输出16-1展示了结果。
C#的索引是基于零的,代码清单16-2中的索引0对应第一个元素,而索引6对应第七个元素。按索引获取元素不会造成搜索操作,而只需快速和简单地“跳”到一个内存位置。List
移除元素使用的是Remove()或者RemoveAt()方法,它们用于移除指定元素,或者移除指定索引位置的元素。
高级主题:自定义集合排序
你可能好奇代码清单16-1的List
但是,假如元素类型没有实现IComparableT),或者默认的比较逻辑不符合要求,又该怎么办呢?为了指定非默认的排序顺序,可以调用List
IComparablecT)和IComparer<T》的区别很细微,但却很重要。前者说“我知道如何将我自己和我的类型的另一个实例进行比较” ,后者说“我知道如何比较给定类型的两个实例”
如果可以采取多种方式对一个数据类型进行排序,但没有哪一种占有绝对优势,就适合使用IComparer