C#中的数组实现为System.Array类的实例,它们只是集合类中的一种。集合类一般用于处理对象列表,其功能比简单数组要多,这些功能是通过实现System.Collections命名空间中的接口而获得的,因此接口的语法已经标准化了。 集合的功能(包括基本函数,例如用[index]语法访问集合中的项。)可以通过接口来实现,该接口不仅没有限制我们使用基本集合类,例如System.Array,相反,我们还可以创建自己的定制集合类。这些集合可以专用于要枚举的对象(即要从中建立集合的对象)。这么做的一个优点是定制的集合类可以是强类型化的。也就是说,从集合中提取项时,不需要把它们转换为正确的类型。另一个优点是提供专门的方法,例如,可以提供获得项子集的快捷方法。 在System.Collections命名空间中有许多接口都提供了基本的集合功能:
-
IEnumerable可以迭代集合中的项。
-
ICollection(继承于IEnumerable)可以获取集合中项的个数,并能把项复制到一个简单的数组类型中。
-
IList(继承于ICollection)提供了集合的项列表,并可以访问这些项,以及其他一些与项列表相关的功能。
-
IDictionary(继承于ICollection)类似于IList,但提供了可通过键码值而不是索引访问的项列表。
System.Array类实现了IList、ICollection和IEnumerable,但不支持IList的一些更高级的功能,表示大小固定的项列表。 11.1.1 使用集合 System.Collections命名空间中的一个类System.Collections.ArrayList也实现了IList、ICollection和IEnumerable接口,但实现的方式比System.Array更复杂。 【示例】 类Animal 1: namespace Ch11Ex01
2: {
3: class Animal
4: {
5: protected string name;
6:
7: public string Name
8: {
9: get
10: {
11: return name;
12: }
13: set
14: {
15: name = value;
16: }
17: }
18:
19: public Animal()
20: {
21: name = "The animal with no name";
22: }
23:
24: public Animal(string newName)
25: {
26: name = newName;
27: }
28:
29: public void Feed()
30: {
31: Console.WriteLine("{0} has been feed.",name);
32: }
33: }
34: }
类Cow
7: Console.WriteLine("{0} has ben milked.",name);
10: public Cow(string name)
1: class Chicken: Animal
2: {
3: public void LayEgg()
4: {
5: Console.WriteLine("{0} has laid an egg.",name);
6: }
7:
8: public Chicken(string name):base(name)
9: {
10:
11: }
12: }
Program代码:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Create an Array type collection of Animal objects and use it.");
Animal[] animalArray = new Animal[2];
Cow myCow1 = new Cow("Deirdre");
animalArray[0] = myCow1;
animalArray[1] = new Chicken("Ken");
foreach (Animal myAnimal in animalArray)
{
Console.WriteLine("New {0} object added to Array collection,Name = {1}",myAnimal.ToString(),myAnimal.Name);
}
Console.WriteLine("Array collection contains {0} objects.",animalArray.Length);
animalArray[0].Feed();
((Chicken)animalArray[1]).LayEgg();
Console.WriteLine();
Console.WriteLine("Create an ArrayList type collection of Animal objects and use it.");
ArrayList animalArrayList = new ArrayList();
animalArrayList.Add(new Cow("Hayley"));
animalArrayList.Add(new Chicken("Rory"));
foreach (Animal myAnimal in animalArrayList)
{
Console.WriteLine("New {0} object added to Array collection,Name = {1}",myAnimal.ToString(),myAnimal.Name);
}
((Cow)animalArrayList[0]).Feed();
((Chicken)animalArrayList[1]).LayEgg();
Console.WriteLine();
Console.WriteLine("Addition manipulation of ArrayList:");
animalArrayList.RemoveAt(0);
((Animal)animalArrayList[0]).Feed();
animalArrayList.AddRange(animalArray);
((Chicken)animalArrayList[2]).LayEgg();
Console.WriteLine("The animal called {0} is at index {1}",myCow1.Name,animalArrayList.IndexOf(myCow1));
myCow1.Name = "Janice";
Console.WriteLine("The animal is now called {0}",((Animal)animalArrayList[1]).Name);
Console.ReadKey();
}
}
【示例说明】
这个示例创建了两个对象集合,第一个集合使用System.Array(这是一个简单的数组),第二个集合使用
System.Collections.ArrayList类。这两个集合都是Animal对象,在Animal.cs中定义。Animal类是抽象类,所以不能进行
实例化。但通过多态性,可以使用集合中项成为派生于Animall类的Cow和Chicken类实例。
下面首先通过比较这两种集合的代码和结果,讨论一下这两种集合的类似操作。
首先是集合的创建。对于简单的数组来说,必须用固定的大小来初始化数组,才能使用它。
Animal[] animalArray = new Animal[2];
而ArrayList集合不需要初始化其大小,所以可以使用下面的代码创建列表anmialArrayList:
ArrayList animalArrayList = new ArrayList();
这个类还有另外两个构造函数。第一个构造函数把现有的集合作为一个参数,把现有集合的内容复制到新实例中;而另一个构造函数通过一个参数设置集合的容量(capactiy)。这个容量用一个int值指定,设置集合中可以包含的项数。但是这并不是真实的容量,因为如果集合中的项数超过了这个值,容量就会自动增大一倍。
因为数组是引用类型的,所以用一个长度初始化数组并没有初始化它所包含的项。要使用一个指定的项,该项还需要初始化,即需要给这个项赋予初始化了的对象:
Cow myCow1 = new Cow("Deirdre");
animalArray[0] = myCow1;
animalArray[1] = new Chicken("Ken");
这段代码以两种方式完成该初始化任务:用现有的Cow对象来赋值,或者通过创建一个新的Chicken对象来赋值。主要区别是前者引用了数组中的对象。
对于ArrayList集合,它没有现成的项,也没有null引用的项。这样就不能以相同的方式给索引赋予新实例。我们使用ArrayList对象的Add()方法添加新项:
Cow myCow2 = new Cow("Hayley");
animalArrayList.Add(myCow2);
animalArrayList.Add(new Chicken("Rory"));
除了语法略有不同外,还可以用相同的方式把新对象或现有的对象添加到集合中。
以这种方式添加完项后,就可以使用与数组相同的语法来重写它们,例如:
animalArrayList[0] = new Cow("Alma");
可以使用foreach结构迭代一个数组,因为System.Array类实现了IEnumerable接口,这个接口的唯一方法GetEnumerator()可以迭代集合中的项目。在代码中,我们写出了数组中的每个Animal对象的信息:
foreach (Animal myAnimal in animalArray)
{
Console.WriteLine("New {0} object added to Array collection,Name = {1}",myAnimal.ToString(),
myAnimal.Name);
}
这里使用的ArrayList对象也支持IEumerable接口;并可以与foreach一起使用,此时语法是相同的。
foreach (Animal myAnimal in animalArrayList)
{
Console.WriteLine("New {0} object added to Array collection,Name = {1}",myAnimal.ToString(),
myAnimal.Name);
}
接着,使用数组的Length属性,在屏幕上输出数组中项的个数:
Console.WriteLine("Array collection contains {0} objects.",animalArray.Length);
也可以使用ArrayList集合得到相同的结果,但要使用Count属性,该属性是ICollection接口的一部分:
Console.WriteLine("ArrayList collection contains {0} objects.",animalArrayList.Count);
简单数组是强类型化的,可以直接访问它们所包含的项类型。所以可以直接调用项的方法:
animalArray[0].Feed();
数组的类型是抽象类型Animal,因此不能直接调用有派生类提供的方法,而必须使用数据类型转换:
((Chicken)animalArray[1]).LayEgg();
ArrayList集合是System.Object对象的集合(通过多态性赋给Animal对象),所以必须对所有的项进行数据类型转换:
((Animal)animalArrayList[0]).Feed();
((Chicken)animalArrayList[1]).LayEgg();
代码的剩余部分利用的一些ArrayList集合功能超出了Array集合的功能范围。
首先,可以使用Remove()和RemoveAt()方法删除项,这两个方法是在ArrayList类中实现的IList接口的一部分。它们分别根据项目引用或索引把项目从数组中删除。在本例中,我们使用后一个方法删除添加在到列表中的第一个项,即Name属性为Hayley的Cow对象:
animalArrayList.RemoveAt(0);
另外,还可以使用:
animalArrayList.Remove(myCow2);
无论采用哪种方式,集合中唯一剩下的项是Chicken对象,可以用下面的方式访问它:
((Animal)animalArrayList[0]).Feed();
对ArrayList对象中的项进行修改,使数组中剩下N个项,其实现方式与保留0~N-1的索引相同。例如,删除索引为0的项,会使其他项在数组中移动一个位置,所以应使用索引0来访问Chicken对象,而不是1。不再有索引为1的项了(因为集合中最初只有两个项),所以如果试图执行下面的代码,就会抛出异常:
((Animal)animalArrayList[1]).Feed();
ArrayList集合可以用AddRange()方法一次添加好几个项。这个方法接受带有ICollection接口的任何对象,该接口包含前面的代码所创建的animalArray数组:
animalArrayList.AddRange(animalArray);
AddRange()方法不是ArrayList提供的任何接口的一部分。这个方法专用于ArrayList类,论证了可以在集合类中执行定制操作,而不仅仅是前面介绍的接口要求的操作。这个类还提供了其他有趣的方法,例如InsterRange(),它可以把数组对象插入到列表中的任何位置,还有用于给数组排序和重新排序的方法。
最后,再回头来看看对同一个对象进行多个引用。使用IList接口中的IndexOf()方法可以看出,myCow1(最初添加到animalArray中的一个对象)现在是animalArrayList集合中的一部分,它的索引如下:
Console.WriteLine("The animal called {0} is at index {1}.",myCow1.Name,animalArrayList.IndexOf(myCow1));
例如,接下来的两行代码通过对象引用重新命名了对象,并通过集合引用显示了新名称:
myCow1.Name = "Janice";
Console.WriteLine("The animal is now called {0}.",((Animal)animalArrayList[1].Name));
|
请发表评论