我们有一种需求,即有必要在创建对象的时候迅速收集他们的引用,从而能遍历并获得其中一个特定的对象,等等.在面向对象变成语言中,可以一种被称为群集(collection)的特殊类型做到这一点.C#最简单的群集类型是定长数组,数组是对象;而Systen.Array是所有数组的基础类.在本文中,我们回顾所有有关数组的内容,并介绍System.Array类的一些更有意思的特征.
当程序运行时很难预料会创建多少个对象,用定长数组存储数量不定的对象,效率太低.System.Conllections命名空间定义了多种可选群集类,我们将会用他们构造SRS-那就是ArrayList类和Hashtable类.
1.数组
System.Array类定义了一系列有用的发方法和property来搜索,排序和修改数组,以及查询长度.
1.数组的Length property
最常用的数组property是int类型的Length property,用来表示数组中所有元素的数量.下面代码演示了如何用Length来求的一维数组的长度:
int[] x = new int[20];
//数组初始化过程已从略... ...
//遍历数组.
//在i等于x.Length之前结束!!!
for(int i = 0;i<x.Length;i++){
Console.WriteLine(x[i]);
}
数组从零开始记数,因此,在for循环中,必须在达到长度上限之前停止,如上例所示.
注意,数组的长度并不反映数组中有多少个元素被赋了值,从技术上说,即便没有明确地在数组中存储任何东西,每个元素都会被自动填充该数组类型中等价于零的值.因此,数组的长度仅仅表明了整个数组的容量;它的容量在一开始声明后被固定了,以后也在不能更改.
2.数组的方法
Array类定义了许多游泳的景泰方法和实体方法,可以用来检查或操作数组;接下来我们将讨论几个常用的方法.关于Array类方法的完整描述请参阅MSDN网站的FCL参考.
前三个方法是静态的.以为着他们必须从作为一个整体Array类上调用:
- public static void Clear (Array array,int startIndex,int length);将数组知道能够范围内的元素重设为与零等价的值.参数包括要清零的数组名称,开始位置(从0开始计数)和需要清零的元素目录;
int[] x = new int [5];
Array.Clear(x,0,x.Length); - public static void Reverse(Array array):调转一个一维数组中的所有元素的次序;
int [] x={1,2,3};
Array.Reverse(x);
//现在x中的元素包括:{3,2,1}.
该方法还有一个覆载版本,能掉转从起始位置开始的规定长度的元素次序:
public static void Reverse(Array array,int startIndex,int length) - public static void Sort(Array array):对一维数组中的元素进行排序.对字符串默认的排序规则是按字母表次序,对数字则按从小到大排序;
string [] names = {"Vijay","Tiger","Phil"};
Array.Sort(names);
//元素的次序现在变成了"Phil","Tiger","Vijay".
该方法有一个覆载版本,能对从其始位置开始规定长度内的元素进行排序:
public static void Sort(Array array, int stratIndex, int length)
*还有一种排序方式,即用户自定义排序规则,但是超出了本书的讨论范围. - 接下来三个方法是实体方法,以为着他们能经由不同的数组实体直接被调用:
- public object GetValue(int index):以一般对象的形式返回一维数组中鼎鼎位置上的元素.如果我们确知返回对象的类型,就能转换它:
String[] names = {"Chris","Sandi","Brennan"};
//将返回对象转换为字符串.
string name = (string) names.GetValue(0);
或
int [] numbers ={11,17,85};
//将返回对象转换为整数
string number = (int) number.GetValue(0);
该方法也有覆载版本,能够返回二维或者三维数组中元素:
public object GtValue(int index1,int index2)
public object GtetValue(int index1,int index2,int index3) - public void SetValue(object value , int index);修改一维数组中指定位置上的元素;
该方法还有修改二维数组或三维数组中指定元素值的覆载版本:
public void SetValue(object value,int index1,int index2,int index3)
*虽然GetValue和SetValue是Array类提供的方法,但索引器的概念更为容易和便与使用.
语法
string name = name[0];
比下面等同的语法更易编写和理解
string name = (string) names.GetValue(0); - public int GetLength(int dimension):返回任意数组中指定维度的长度.例如,要得到一个二维数组中第一维的长度,用GetLength(0).(对于一维数组,只需用Length property来判断长度.)
2.ArrayList类
0.ArrayList是一个简单的,动态改变长度的一维有序列表,允许存储不同数量的对象引用,而不必操心容器长度.ArrayList在逻辑上等同于一维数组,但长度能随需应变.
ArrayList能够包含任意类型的元素(因为在C#所有种类元素都是对象),而且,如果有必要,还可能在同一个ArrayList中混合放置这些不同类型的元素.
ArrayList类在System.Collections命名空间中的定义.要引用ArrayList类,在代码短员开头放置以下using知识符:
using System.Collections;
或者使用全名:
System.Collectiongs.ArrayList.
1.创建一个ArrayList
可以使用ArrayList类提供的三个构造器之一实体化一个ArrayList对象.
- 最简单的形式是无参数构造器:
ArrayList coursesTaken = new ArrayList();
该构造器创建一个内空的,缺省容另为16个元素的ArrayList.当元素数量达到当前数量上限时,ArrayList的容量自动翻倍. - 第二种形式是接受一个整数参数,该参数代表ArrayList的初始容量;如:
ArrayList students = new ArrayList(400);
当我们确知ArrayList中将会放入最大对象引用时,应用这种形式的构造器.把ArrayList初始容量定为大于缺省的16个元素,减少了从新设定容器的次数,从而提升了性能. - 第三种构造器接受任何合适的C#群集对象----即,所有实现恶劣ICollection接口的类的对象,包括Systen.Collections类的对象和System.Array类的对象----作为参数,然后复制传入群集的内容,组装为新构造的ArrayList对象.
//创建一个Course对象数组
![]()
Course[] course = new Course [3];
Course[0] = new Course ("Math 101");
Course[1] = new Course("Physics 250");
Course[2] = new Course("Management 283");
//其他细节从略
//在后面的饿程序中,用它来初始化一个ArrlyList.
ArrayList coursesTaken = new ArrayList(course);
在上面的代码片段中,我们初始化了一个ArrayList,容纳一个Course数组.注意俩个群集都是指向相同的对象.
2.ArrayList property
ArrayList 声明了多个attribute来返回自身信息.
- Capacity property,用来得到ArrayList的容量:(如果试图在代码中将他的长度减小到不能容纳已有元素时,一个ArgumentOutOfRangeException异常会被抛出)
- Count property ,ArrayList中当前的元素数量;
- 为了得到一个ArrayList中的某个元素,ArrayList类定义恶劣一个特殊的索引器property,允许我们象普通数组一样访问里面的元素----在方括号中输入要索引的整数值,索引器返回一个普通对象引用,被索引的元素被转换为原本类型.
//这个例子演示了这些property
Course c1 = new Course("Math 101");
Course c2 = new Course("Physics 250");
Course c3 = new Course("Management 283");
//正确地使用ArrayList索引器(注意,看起来象一个数组!)
coursesTaken[0] = c1;
coursesTaken[1] = c2;
coursesTaken[2] = c3;
//使用Capacity和Count property
Console.WriteLine("capacity = " +coursesTaken,Capacity);
Console.WriteLine(no. of elements =" +coursesTaken.Count);
//用索引器取出ArrayList中的元素
for (int i = 0;i<coursesTaken.Count;i++){
//用索引器取出ArrayList中的元素
//将一个普通对象重新转换为Course对象引用
Course c = (Course) courseTaken[1];
//在c上调用Course方法
Console.WriteLine(c.Name);
}
这个例子说明。在ArrauLis中加入不同类型的元素是很危险的。ArrayList中的元素被遍历转换为Course对象。每个Course对象中 Name property被调用。如果ArrayList中每一个元素都是Course对象(或者Course类派生的类型对象(),就能正常工作。但是如果不同类型的元素存在,就会抛出一个InvalidCastException异常.在本章稍后部分“集群与转换 ”一节中,我们将会看到更多混合类型导致错误的例子。
3. ArrayList类的方法
常用的ArrayList方法如下:
- public virtual int Add(object value):在ArrayList末尾添加一个对象引用,若容器不足自动扩展。前面virtual关键字表示允许派生类覆载这个方法。返回一个int类型,表示传如参数在ArrayList中的位置。
- public void Add(ICollection c);在ArrayList末尾添加特定群集的内容;
- public void SetRange(int starIndex,ICollection c): 从指定其始处用另一ICollection对象取代ArrayList原有元素。c中的元素大雨ArrayList将会自动扩展。
- public IEnumerator Get Enumerator();获取一个IEnumerator(一种特殊类型的类型对象)对象,可用来遍历ArrayList中的元素。我们将在本章后面部分讨论IEnumerator;
- public int IndexOf(object obj):寻找一个指定的对象引用,如果找到,则返回第一个匹配位置(从0开始计数)。如果没找到返回-1;
- piblic bool Contains(object obj):寻找一个指定的对象引用,如果找到,返回true,否则返回false;
- public void RemoveAt(int index):将指定位置的元素剔除,并且“填上”空洞。Count property将会递减,而Capacity则保持不变。如果指定的索引大于Count值或者小于0,将抛出一个ArgumentOutPfRangeException异常
- public void Remove(object obj): 在ArrayList中搜寻指定的对象引用,如果找到,则把第一个找到的对象从ArrayList中移除。Count property将会减1,而Capacity则会保持不变,如果希望删除掉所有obj,在一个while循环中组合使用Contains和Remove方法:
while(arraylist.Contains(x)){
arraylist.Remove(x)
} - public void Sort(); 对ArrayList中的元素排序。默认按照字母排序对string 元素排序,按照从小到大顺序对数值型元素排序;
*该方法还有一个覆载版本,允许拥护定制对任意类型的排序算法,但对定制排序算法的讨论已经超出本书的范围了。 - public void Clear();清空整个ArrayList.Count property 被设为0,Capacity不变;
- public object[] ToArray();创建一个Object数组,并将ArrayList中的元素拷贝进该宿主。
ArrayList类中还有很多方法!如果需要完整的ArrayList方法列表,请参考阅读MSDN网站上的FCL参考。
3.Hashtable类
Hastable类提供了c#中另外一种群集管理对象的引用途径。Hastable比ArrayList略显复杂,因为它允许我们用唯一关键词直接访问指定对象;Hastable是字典群集类饿一种实现,关键次和对象本身可以是任何一种类型;关键词经常是但非一定是string类型。
和ArrayList一样,Hastable可以在System.Collections的命名空间中找到。要使用Hastable简称,需要在源程序头部加上using System.Collection知指示符,或者用它的全名----System.Collections.Hashtable
1.可以使用Hastable类中声明的任何一个构造器创建Hashtable对象。实例化Hastable的最简单手段,是用无参数的构造器创建一个空的Hastable ,我们使用Add方法插入所需要的对象,方法头如下:
public void Add(object key ,object value)
注意,必须为添加到Hastable的没个元素指定一个关键词,通过它能在以后重新得到该元素;在本例中,使用一个string对象作为关键词----学生的社会保障号(Ssn):

//创建一个Hastable实体(卡蛋板)
Hastable students = new Hastable();
//创建多个Student对象(“鸡蛋”)。
Student s1 = new Student("123-45-6789","John Smith");
Student s2 = new Student("987-65-4321","Mary Jones");
Student s3 = new Student("654-32-1987","Jim Green");
//在Hastable中存储这些Student对象的句柄,
//用每个Student对象的Ssn property
//(恰好被声明为string)作为没项的关键词。
students.Add(s1.Ssn,s1);
students.Add(s2.Ssn.s2);
students.Add(s3.Ssn,s3);
//Hashtable类定义了一个索引器,用来获取或设置Hastable中的元素。同使用ArrayList一样,索引器通过一对放括号表示;但在Hashtable中,放括号里
//面放置元素的关键词:
//注意,和ArrayList一样,得到对象后要进行转换。
Student s = (Student) students[["123-45-6789"];//得到对象引用,表示学生Hohn Smith
Console.WriteLine("name is " + s.Name);
//或者。如另一个例子:
//伪代码。
string id = retrieve student ID number from a GUI;
Student s = (Student) students[id];
注意,如果希望按对象的原来类型去操作从Hashtable的到的对象(本例中是一个Student 对象),必须惊醒转换操作,就象从ArrayList中得到一个对象一样。
(索引器返回一个普通的对象引用,被索引的元素被转换为原本的类型)
2.Hashtable类的property
Hashtable和ArrayList一样,拥有Count prperty和索引器,使用方法也相同。除次之外,Hashtable类还声明了许多特有的prperty
- Keys property:返回一个ICollection对象,由Hashtable中的所有关键词组成
- Values property:返回一个ICollection对象,由Hastable中所有关键词的值组成
3.Hashtable类中的方法
Hashtable类中常用的方法如下:
- piblic void Add(object key,object value ):前面已提到,该方法使用第二个参数表示的对象引用作为关键词,把第一个对象应用插入到Hashtable中。如果在该关键词标注的位置已经有对象存在,将抛出一个ArgumentException异常。因此,应该先使用后面的ContainKey方法,确认该关键词没有被使用过,这非常重要。
- public bool ContainsKey(object key): 如果指定关键词标注的条目在Hashtable中存在则返回true,反之返回false
下面演示了组合ContainKey方法与Add方法,确保不尝试覆盖Hashtable中已存在的条目:
Student s = new Student ("111-11-1111","Arnold Brown);
if (stdents.ContainsKey(S.Ssn)){
//哇!有重复,我们需要决定怎么办
//细节从略![]()
}
else{
students.Add(s.Ssn,s);//Ok,因为没有发现重复。
}
![]()
- public bool ContainsValue(object value):寻找指定的值,不考虑其关键词,如果找到则返回true,反之则返回false;
- public void Remove(object key):从Hashtable中移除指定关键词对应的对象引用;注意,对象本身存在于Hashtable以外,不会受到影响;
- public IDictionaryEnumerator GetEnumerator();返回一个IDicitonaryEnumerator对象,可用来检测目前在Hashtable中存储的“关键词-值”对,我们将在下一节讨论枚举器(enumerators);
- public void Clear();清空Hashtable,恢复到初始状态。Count property设为0。
4.集群和转换
在C#群集中,唯有Array可以限制插如Object的类型.即声明 一个Array时,必须声明插入项的类型:
int [] x = new int[20];//限制x只能是int类型.
而在c#中的其他正式群集中,声明群集时,不能限制插入的Object类型;在前面提到,c#群集,除Array外,都被设计成能持有一般对象,因此,如果打算利用多太的好处,在想群集插入对象时,就唏嘘确保被插入的对象同文,同种.c#编译器不会组织我们把类型不一致的对象插入群集中,但如果在取出对象后试图"不正确地"操作对象,c#编译器或运行环境就会报错.
为了演示这个概念,我们看一个简单的例子.我们将使用一个 ArrayList群集类,但同样的概念对于c#其
System.Collection类也管用.假定定义了一个Student类,其中声明一个CalculateGPA方法.
{//细节从略.
public void CalculateGPA(){
//细节从略.
}
}
//再声明一个Professor类,但不声明CalculateGPA方法
public class Professor{
//细节从略----没声明ClaculateGPA方法
}
//我们在前面已经学的到,往同一ArrayList中天家不同的Student和Professor对象,编译器不会报错,因为非Array群集
//并不限制添加项的类型:
Stidemt s = new Student();
Student t = new Student();
Professor p = new Professor();
Professor q = new Professor();
//不能将ArrayList声明为特定类型.
ArrayList people = new ArrayList();
//在群集中混合加入Student和Professor对象引用
people.Add(s);
people.Add(p);
people.Add(q);
people.Add(t);
people[0].CalculateGPA();
做为程序的编写者,我们知道,ArrayList零元素位置上的元素是一个Student,所以让我们通过索引器来得到这个元素,并调用其CalculateGPA方法:
people[0].CalculateGPA();
这样做看起来没错,但试图编译时就会产生一个错误:
Error CS0117:'Object' does not contain for 'CalculateGPA' 的定义
即便ArrayList的零元素在运行时就是Student对象,编译器也只认为索引器返回的是一个一般对象引用.在编译器眼中,people[0] 只是一个一般对象引用,而且该对象没有声明CalculateGpa方法----只有Student类声明过这个方法----这行无法编译.
解决这个编译错误的办法是,在调用CalculateGPA方法之前,强制转换ArrayList索引器的返回值为Student对象.
Student s2 = (Student) people[0];
s2.CalculateGPA();
或者写成一行代码
((Student) people[0]).CalculateGPA();
上面2种手段,都是编译器可以接受的,因为我们要求编译器相信,在运行时,提及的对象引用的确志向一个Student对象;编译器知道, Student类定义了一个CaculateGPA的方法,所以就万事大吉了!
但这样仍有一个潜在的问题:如果ArrayList群集混合存储了Student和Professor对象引用,且我们想遍历整个群集,这样就不能把每个元素转换为Student对象,并调用CalculateGPA方法,因为Professor类并未定义CalculateGPA方法:
for (int i = 0; i<people.Count; i++){
Student x = (Student) people[i];//第i个元素不一定是Student对象引用!
}
上面的代码可以编译通过,因为我们再一次要求编译器相信,群集中所有元素都是Student对象;但在实际执行时,当遇到第一个Professor引用,就会抛出一个InvalidCastException异常,程序也将停止执行,因为根本没办法把 Professor类转换成Student类.如果打算在一个循环结构中遍历真个混杂了Professor对象和Student读乡的people群集,只能如此这般:
*把所有元素看作一般对象(generic objects);
*把所有元素转换为一个公共超类(common supertype).
我们研究一下上述俩中手段.
如果把群集中所有对象看作一般对象,那么编译器允许调用的每个object应用的唯一方法,只是Object类中已定义的方法:
for (int i = 0;i <people.Count;i++){
//不能转换对象引用.
object x = people[i];
//因此唯一能调用的x方法是Object类定义的方法.
Console.WriteLine(x.ToString());
然而,如果群集中的不同对象类型拥有公共超类----比方说Student和Professor都派生字共同的Person基类----就可以将所有对象引用都转换成Oerson对象的引用,因为根据继承的"is a"特点,Student对象是Person对象,Professor对象也是Person对象.在这种情况下,我们可以调用对象在Person类中定义的共有方法:
for( int i = 0;i< people.Count;i++){
Person x = (Person) people[i];//转换为一个公共超类.
x.printAddress();//在Person中总定义的一个方法
}
System.Collections 群集,例如ArrayList或Hashtable,将插入的所有项视为一般对象引用,所以,程序员必须记得存放到群类集中的每个对象引用类型,这样,当重新获取他们时,才能够转换为正确的(公共基类)类型.一个助记的方法是,在群集生命后面加上注释,指出在其中存放的对象引用类型:
ArrayList coursesTaken;//Course 类型的对象引用.
5.用枚举器 (Enumerator)遍历群集:
例如我们可能需要获得一个ArrayList中所有Student对象引用,从而计算出学期的最后成绩.一种遍历ArrayLsit的方法是用for循环:
ArrayList enrollment = new ArrayList();// Student对象引用群集
//...细节从略
//遍历整个ArrayList并处理所有学生成绩.
通过这种方式处理ArrayList中的每个元素,是可能有的,因为我们能够经由索引定位到ArrayList中的一个指定元素:例如enrollment[i].
另外还有一种遍历System.Collections群集中每个元素的手段,即使用一种化名叫枚举器(enunerator)的特殊对象类型.枚举器是一种遍历群集的机制,当得到一个群集的枚举器时----比如一个ArrayList的枚举器----可以概念性地任务它复制了原始群集中的内容,就好象为了做电话营销而复印某人的通讯录(Person对象引用群集)
然后,我们遍厉每份"复印件"(),"在每个句号上打叉"(处理每个对象引用了直至到达枚举器末尾).
Student s = (Student) enrollment[i];
s.ComputeFinalGrade();
}
1.IEnumerator接口
前面提到过,ArrayList类通过以下头语句定义了一个GetEnumerator方法:
public virtual IEnumerator GetEnumerator()
该方法返回的类型,IEnumerator,是一个定义在System.Collections命名空间中的接口.IEnuerator对象被调用时,表现为一个ArrayList的临时拷贝,拥有以下方法:
- bool MoveNext();使用枚举器指向群集中下一个元素.如果成功指向则返回tru,如果到达群集尾则返回false
- void Reset(): 将枚举器指向第一个值的前面位置,这样,下次调用MoveNext方法时,游标将定位到群集中的第一个元素.
下例演示了如何使用IEnumerator中的功能.我们使用以下简单版本的Course类:
public class Course
{//字段
private string name;
//构造器
public Course(string n){
name = n ;
}
//Property.
public string Name{
//细节从略
}
}
//下面代码用与驱动程序运行:
using System.Collectiongs;
public class EnimDemo
{
static void Main(){
ArrayList coursesTaken = new ArrayList();
Course c1 = new Course("Math 101");
Course c2 = new Course("Physics 250");
Course c3 = new Course("Management 283");
//在ArrayList中插入Course对象引用.
courseTaken.Add(c1);
courseTaken.Add(c2);
courseTaken.Add(c3);
//为ArrayList创建一个枚举器
IEnimerator enum = courseTaken.GetEnumerator();
//使用枚举器遍历群集
while (enum.MoveNext()){
//用Currnt property得到当前元素,然后将其转换为Course对象引用
Course c = (Course)enum.Current;
//现在可以操作Course对象一样操作c.
Console.WriteLine(c.Name);
}
}
}
程序运行输出以下结果:
Math 101
Physics 250
Management 283
2.IDictionaryEnumerator接口
我们已经了解到,Hashtable是用"名--值"对形式存储数据的一种群集.对于Hashtable有一种特殊的枚举器--IDictionaryEnumerator.前面提到过,Hashtable类声明了以下方法,来为给定的Hashtable得到一个IDictionaryEnumerator:
public virtual IDictionaryEnumerator GetEnumerator()
IDictionaryEnumerator接口派生自IEnumerator类,并继承了我们之前讨过的MoveNext和Reset方法,IDictionaryEnumerator接口还定义了几个特有property,特别是Key和Value,他们分别返回当前元素的关键词和对应的值.
下面是一个通过IDictionaryEnumerator得到Hashtable中元素的例子.我们从Student类的简单版本开始:
{
private string name;
private string ssn;
//构造器
public Student(strig s ,string n){
ssn = s;
name = n;
}
//property
public string Name{}//细节从略
public string Ssn{}//细节从略
}
//下面是IDictionaryEnumerator的例子:
using System;
using System.Collections;
public class EnumDemo2
{
static void Main(){
//创建一个Hashtable实体。
Hashtable student()
//实体化几个Student对象
Student s1 = new Student("123-45-6789","Chris Williams");
Student s2 = new Student("987-65-4321","Yukio Koyari");
Student s3 = new Student("654-32-1987","Maria Lopez");
//将他们存储在Hashtable,使用Ssn作为关键词
student.Add(s1.Ssn,s1);
student.Add(s2.Ssn,s2);
student.Add(s3.Ssn,s3);
//为Hashtable创建一个IDictionaryEnumerator
IDictionaryEnumerator遍历群集。
while(enum.MoveNext()){
//从群集中得到下一个Student对象。
Student s = (Student) enum.Value;
Console.WriteLine(s.name+":"+s.Ssn);
//运行程序将输出以下结果:
Maria Loez:654-32-1987
Yukio Koyari:987-65-4321
Chris Williams:123-45-6789
}
注意,打印出来的学生信息,和当初添加到Hashtable中的顺序并不一样。通过IDictionaryEnumerator不能按照特定顺序遍历Hashtable;只能保证遍历所有项.
6.遍历一般ICollections
记得前面讨论Hashtable时提到过,ICollection有俩个property--Keys和Values.让我们看看如何遍历一般ICollection中的元素.
ICollection对象只有一种名为CopeTo的方法,方法头如下:
void CopyTo(Array array,int index)
CopyTo方法用来将一个ICollections的内容拷贝到一个Array对象中.回忆前面的内容就会想起来,Array类是c#中多有数组类型的父类.index参数指明拷贝起使处.一旦关键词或值被传入数组,数组中的元素就能用普通手段访问.下面是一个通过关键词和对应值遍历Hashtable中元素的例子,我们使用前面定义的Student类,但驱动代码不同.
using System;
using System.Collections;
public class EnumDemo3
{
static void Main(){
//创建一个Hashtable实例.
hashtable students = new Hashtable();
//初始化几个Student对象
Student s1 = new Student("123-45-6789","John Smith");
Student s2 = new Student("987-65-4321","Yukio Koyari");
Student s3 = new Student("654-32-1987","Maria lopez");
//将他们存储在Hashtable,使用Ssn做为键名
student.Add(s1.Ssn,s1);
student.Add(s2.Ssn,s2);
student.Add(s3.Ssn,s3);
//使用Keys和Values property,从hashtable创建俩个ICollection,
ICollection keys = students.Keys;
ICollection values = students.Values;
//创建string 和Student数组,保存keys和values.
string [] studentIDs = new string[students.Count];
Student[] studentObjects = new Student[students.Count];
//将ICollections呢容拷贝进数组.
keys.CopyTo(studentIDs,0);
values.CopyTo(studentObjects,0);
//遍历
Console.WriteLine("student IDs(key):");
for(int i = 0 ;i<studentIDs.Length;++i){
Console.WriteLine("Student ID:"+studentID[i]);
}
Console.WriteLine(Students (Values):");
for(int i = 0;i<studentObjects.Length;++i){
Console.WriteLine(s.Name+":"+s.Ssn);
}
}
}
程序运行输出以下结果:
Student IDs(Keys):
Student ID: 654-32-1987
Student ID: 987-65-4321
Student ID: 123-45-6789
Student (Values):
Maria Lopez: 654-32-1987
Yukio Koyari: 987-65-4321
John Smith: 123-45-6789
}7.foreach循环
Foreach循环是C#控制结构流程之一.foreach循环提供了遍历数组或ICollection中元素的另一种手段.
foreach循环的一般语法如下:
foreach (type variablem_name in collection_name){
//将要执行的代码
}
在foreach关键字后面的圆括号中,我们发现
- 将被处理的群集中条目的类型----从群集中得到的条目被自动转换成该类型;
- 与群集中的条目构成一对一引用关系的局部变量
- 要搜索的群集名称,前面加上int关键字
例如:一个int数组
int sum = 0 ;
foreach (int x in numbers){
//可以对x做任何事;注意不需要转换类型;
//x被自动转换为int
Console.WriteLine("Adding"+x+ "to sum"):
sum += x;
}
//上面的代码将产生以下输出
Adding 1 to sum

Adding 3 to sum

Adding 5 to sum

Adding 7 to sum

Adding 9 to sum

Sum = 25
//再如另外一个例子
//Student 对象引用群集
Arraylist studentBody = new ArrayList();
//细节从略
foreach (Student s in stadentBody){
//s自动指向Student
s.Compute GPA();
}
//foreach 语句在每次循环当中都会从指定类型的元素集合中取出一个元素,并执行foreache语句所包含的代码块.
//注意,一旦进入一个foreach代码块马厩不能试图修改foreach引用变量的值;即,下面的
//代码无法被正常编译:
foreach (Student s in studentBody){
//这将不能被编译,引用变量s是只读的.
s = (Student) studentBody[0];
}
error CS1640:can not assign to 's' because it is read-only
//当然,由S所指代的对象是可访问(accessible)切可修改(modifiable)的,情况与
//任何其他拥有引用对象一样:
foreach(student s in studentBody){
//可被执行
s.Name = "?";
}
下面上一最后一个关于foreach循环的例子,它使用foreach循环,遍历一个混杂存储了Professor对象和Student对象的ArrayList中的元素,假定Professor和Student类都是从Person类派生而来,我们将把它们的公共超类Person作为ArrayList中搜索的类型,ArrayList中的每个Person对象的名字将显示出来.
using System;
suing System.Collections;
public class FpreachDemo
{
static void Main(){
//创建一个ArrayList里面包含Student和Professor对象.
ArrayList people = new ArrayList();
people.Add(new Professor("Jacquie Barker"));
people.Add(new Student("Maria vasquez"));
people.Add(new Professor("John Carson"));
people.Add(new Professor(""Mike Vito));
people.Add(new Student("Jackson Palmer"));
//使用foreach循环遍历ArrayList,得到每个Person对象引用,并打印他们的名字.
foreach(Person p in people){
Console.WriteLine(p.Name);
}
}
}
输出结果将会是:
Hacquie Barker
Maria Vasquez
Jon Carson Mike Vito
Jackson Palmer
当然,如果foreach语句中的类型与群集类中某些条目不匹配,在运行时的隐式类型转换竟导致抛出一个InvalidCastException异常,就象我们尝试做非法的显示转换一样


浙公网安备 33010602011771号