.NET 框架集合:基本接口

来源:互联网 发布:linux自动挂载光盘 编辑:程序博客网 时间:2024/05/20 00:12

.NET 框架集合:基本接口

为了解 .NET 框架集合,先了解一些几乎所有集合都实现的接口是很有用的。

IEnumerable

所有集合都实现至少两种接口:ICollectionIEnumerable

IEnumerable 只有一种方法,称为 GetEnumerator。它返回一个计数器对象,该对象实现 IEnumerator 接口。

C# 和 Visual Basic.NET 中的 foreach 语句依赖于实现 IEnumerable 的集合。

IEnumerator

IEnumerator 接口允许您枚举集合,换言之,即访问每个元素。如果集合是有序集合(如数组或列表),该访问将是按顺序进行的;而在无序的集合(如散列表)中,访问没有特定的顺序。IEnumerator 有一个只读属性,称为 Current,该属性返回一个对当前对象的引用。它还有两个方法:MoveNext,用于移至集合中的下一个对象,设置 Current 指向该对象,并且如果没有越出结尾就返回 True;Reset,用于在集合的开头部分之前将 Current 指针重新设置为不确定的值。创建计数器或调用 Reset 后首次访问 Current 之前,“必须”先调用 MoveNext,因为 Current 引用最初是不确定的。

请注意,集合并“不”自行实现 IEnumerator;相反,每次调用 GetEnumerator 时集合都返回一个独立的计数器对象。

下面有一个有关枚举集合的示例,既使用了 foreach,又直接使用了枚举接口。

ICollection

ICollection 是对 IEnumerable 的扩展,并新增三个只读属性和一个方法。三个属性为:Count,用于返回集合中的对象数;IsSynchronized,如果对于多线程访问,对集合的访问是同步的,该属性就返回 True;SyncRoot,该属性返回的对象可用于对跨线程的集合访问进行同步(如果还没有进行同步)。一个方法为:CopyTo,用于将集合中的元素复制到数组,并在指定的数组位置开始。

使用 ICollection 和 IEnumerable 的示例

每个集合都可以告诉您集合中含有多少元素,都可以被枚举和复制,并且能够被同步。因此,可以将“任何”集合传递给下列方法:

public static void PrintCollection(String info, ICollection c) {   Console.Write("{0}:集合有 {1} 个元素:", info, c.Count);   foreach (Object o in c) { // 编写循环的最简便方法      Console.Write("{0} ", o);   }   Console.WriteLine();}public static void PrintCollectionSync(ICollection c) {   Console.WriteLine("同步访问(此处不需要)");   lock (c.SyncRoot) {  // 锁定 SyncRoot   //--仅用于演示,仅在多线程访问时才需要   // 以下循环与上面的 foreach 等价      IEnumerator e = c.GetEnumerator();      while (e.MoveNext()) { // 首次移动         Console.Write("{0} ", e.Current);      }      Console.WriteLine();   }}public static Object [] CopyToArray(ICollection c) {   Object [] retVal = new Object[c.Count];   c.CopyTo(retVal, 0);   return retVal;}

请注意,只要编程语言支持,foreach 就是首选的访问集合的方法,C# 和 Visual Basic.NET 都具有这一特征。除非有合理的理由,否则就应该使用 foreach,因为使用它可以允许编译器生成更适合的代码供特定的集合访问使用。无论您是否使用同步(在上述的第二个方法中,我们这样做了,但除非多个线程可以同时访问同一集合,否则没有必要同步),都应该如此。

在下面的示例中,我们要传入两个不同的集合:一个 Int32 数组和一个 Object 数组。可以自行对其他集合试用这些方法调用:

Int32 [] intArr = {0, 1, 2, 3, 4};PrintCollection("intArr", intArr);Object [] oArray = CollectionExample.CopyToArray(intArr);PrintCollection("oArray(从 intArr 复制得到)", oArray);PrintCollectionSync(oArray);

IList

许多集合(特别是那些排了序因而可编制索引的集合)还实现 IListIList 针对可编制索引的有序列表扩展了 ICollection(可能您还记得,ICollection 是对 IEnumerable 的扩展)。IList 新增了一个属性(在 Beta 2 及更高版本中增加三个属性)和七个方法。

一个属性为 Item,用于获取索引并返回相应的列表元素。(ItemC# 的索引函数,因此对集合 Foo 而言,在 C# 中访问 Item 属性所用的语法是 Foo[indexer]。) 在 Beta 2 及更高版本中,还有两个属性:IsFixedSizeIsReadOnly。它们在列表大小固定或为只读的情况下分别返回 True。

Ilist 中有许多方法:Clear 可清除列表;Add 可在列表中添加项目,通常添加到结尾(取决于实际实现);Insert 可在列表中指定的索引处插入项目;Remove 可删除某一对象的第一个实例;RemoveAt 可删除指定索引处的对象;Contains 可表明列表是否包含某个值;IndexOf 返回列表中值所在位置的索引。请注意,在大小固定的集合(如数组)上不能使用 AddInsertRemoveRemoveAt 方法。如果这样做,就会导致异常错误。

但我们可以轻松地从数组创建 ArrayList — 我们可以通过它演示 IList 方法。若要创建 ArrayList 并进行调用,要编写的代码很简单:

ArrayList al = new ArrayList(intArr);ListTest(al);

ListTest 方法也相当简单:

public static void ListTest(IList l) {   PrintCollection("原列表", l);         l.Add(5);   PrintCollection("Add(5) 之后", l);         l.RemoveAt(2);   PrintCollection("RemoveAt(2) 之后", l);         l.Remove(3);   PrintCollection("Remove(3) 之后", l);         l.Insert(1, 7);   PrintCollection("Insert(1, 7) 之后", l);         Console.WriteLine("包含 55?{0}", l.Contains(55));   Console.WriteLine("IndexOf(4) 是 {0}", l.IndexOf(4));   l.Clear();   PrintCollection("清除之后", l);}

这种情况下,输出为:

原列表:集合有 5 个元素:0 1 2 3 4Add(5) 之后:集合有 6 个元素:0 1 2 3 4 5RemoveAt(2) 之后:集合有 5 个元素:0 1 3 4 5Remove(3) 之后:集合有 4 个元素:0 1 4 5Insert(1, 7) 之后:集合有 5 个元素:0 7 1 4 5包含 55?FalseIndexOf(4) 是 3清除之后:集合有 0 个元素: