}
}
该迭代显示了所有的行和每一行中的各个元素:
row:
0,element:
0,value:
1
row:
0,element:
1,value:
2
row:
1,element:
0,value:
3
row:
1,element:
1,value:
4
row:
1,element:
2,value:
5
row:
1,element:
3,value:
6
row:
1,element:
4,value:
7
row:
1,element:
5,value:
8
row:
2,element:
1,value:
9
row:
2,element:
2,value:
10
row:
2,element:
3,value:
11
5.4 Array类
用括号声明数组是C#中使用Array类的记号。
在后台使用C#语法,会创建一个派生于抽象基类Array的新类。
这样,就可以使用Array类为每个C#数组定义的方法和属性了。
例如,前面就使用了Length属性,还使用foreach语句迭代数组。
其实这是使用了Array类中的GetEnumerator()方法。
5.4.1 属性
Array类包含的如下属性可以用于每个数组实例。
本章后面还将讨论其他更多的属性。
表 5-1
属性
说明
Length
Length属性返回数组中的元素个数。
如果是一个多维数组,该属性会返回所有阶的元素个数。
如果需要确定一维中的元素个数,则可以使用GetLength()方法
LongLength
Length属性返回int值,而LongLength属性返回long值。
如果数组包含的元素个数超出了32位int值的取值范围,就需要使用LongLength属性,来获得元素个数
Rank
使用Rank属性可以获得数组的维数
5.4.2 创建数组
Array类是一个抽象类,所以不能使用构造函数来创建数组。
但除了可以使用C#语法创建数组实例之外,还可以使用静态方法CreateInstance()创建数组。
如果事先不知道元素的类型,就可以使用该静态方法,因为类型可以作为Type对象传送给CreateInstance()方法。
下面的例子说明了如何创建类型为int、大小为5的数组。
CreateInstance()方法的第一个参数应是元素的类型,第二个参数定义数组的大小。
可以用SetValue()方法设置值,用GetValue()方法读取值:
ArrayintArray1=Array.CreateInstance(typeof(int),5);
for(inti=0;i<5;i++)
{
intArray1.SetValue(33,i);
}
for(inti=0;i<5;i++)
{
Console.WriteLine(intArray1.GetValue(i));
}
还可以将已创建的数组强制转换成声明为int[]的数组:
int[]intArray2=(int[])intArray1;
CreateInstance()方法有许多重载版本,可以创建多维数组和不基于0的数组。
下面的例子就创建了一个包含2×3个元素的二维数组。
第一维基于1,第二维基于0:
int[]lengths={2,3};
int[]lowerBounds={1,10};
Arrayracers=Array.CreateInstance(typeof(Person),lengths,lowerBounds);
SetValue()方法设置数组的元素,其参数是每一维的索引:
racers.SetValue(newPerson("Alain","Prost"),1,10);
racers.SetValue(newPerson("Emerson","Fittipaldi"),1,11);
racers.SetValue(newPerson("Ayrton","Senna"),1,12);
racers.SetValue(newPerson("Ralf","Schumacher"),2,10);
racers.SetValue(newPerson("Fernando","Alonso"),2,11);
racers.SetValue(newPerson("Jenson","Button"),2,12);
尽管数组不是基于0的,但可以用一般的C#记号将它赋予一个变量。
只需注意不要超出边界即可:
Person[,]racers2=(Person[,])racers;
Personfirst=racers2[1,10];
Personlast=racers2[2,12];
5.4.3 复制数组
因为数组是引用类型,所以将一个数组变量赋予另一个数组变量,就会得到两个指向同一数组的变量。
而复制数组,会使数组实现ICloneable接口。
这个接口定义的Clone()方法会创建数组的浅副本。
如果数组的元素是值类型,就会复制所有的值,如图5-5所示:
intintArray1={1,2};
intintArray2=(int[])intArray1.Clone();
图 5-5
如果数组包含引用类型,则不复制元素,而只复制引用。
图5-6显示了变量beatles和beatlesClone,其中beatlesClone是通过在beatles上调用Clone()方法来创建的。
beatles和beatlesClone引用的Person对象是相同的。
如果修改beatlesClone中一个元素的属性,就会改变beatles中的对应对象。
Person[]beatles={
newPerson("John","Lennon"),
newPerson("Paul","McCartney"),
};
Person[]beatlesClone=(Person[])beatles.Clone();
图 5-6
除了使用Clone()方法之外,还可以使用Array.Copy()方法创建浅副本。
但Clone()方法和Copy()方法有一个重要区别:
Clone()方法会创建一个新数组,而Copy()方法只是传送了阶数相同、有足够元素空间的已有数组。
提示:
如果需要包含引用类型的数组的深副本,就必须迭代数组,创建新对象。
5.4.4 排序
Array类实现了对数组中元素的冒泡排序。
Sort()方法需要数组中的元素实现IComparable接口。
简单类型,如System.String和System.Int32实现了IComparable接口,所以可以对包含这些类型的元素排序。
在示例程序中,数组name包含string类型的元素,这个数组是可以排序的。
String[]names={
"ChristinaAguillera",
"Shakira",
"Beyonce",
"GwenStefani"
};
Array.Sort(names);
foreach(stringnameinnames)
{
Console.WriteLine(name);
}
该应用程序的输出是排好序的数组:
Beyonce
ChristinaAguillera
GwenStefani
Shakira
如果
修改Person类,使之执行IComparable接口。
对LastName的值进行比较。
LastName是string类型,而String类已经实现了IComparable接口,所以可以使用String类中CompareTo()方法的实现代码。
如果LastName的值相同,就比较FirstName:
publicclassPerson:
IComparable
{
publicintCompareTo(objectobj)
{
Personother=objasPerson;
intresult=this.LastName.CompareTo(
other.LastName);
if(result==0)
{
result=this.FirstName.CompareTo(
other.FirstName);
}
returnresult;
}
//…
现在可以按照姓氏对Person对象数组排序了:
Person[]persons={
newPerson("Emerson","Fittipaldi"),
newPerson("Niki","Lauda"),
newPerson("Ayrton","Senna"),
newPerson("Michael","Schumacher"),
};
Array.Sort(persons);
foreach(Personpinpersons)
{
Console.WriteLine(p);
}
使用Person类的排序功能,会得到按姓氏排序的姓名:
EmersonFittipaldi
NikiLauda
MichaelSchumacher
AyrtonSenna
如果Person对象的排序方式与上述不同,或者不能修改在数组中用作元素的类,就可以执行IComparer接口。
这个接口定义了方法Compare()。
IComparable接口必须由要比较的类来执行,而IComparer接口独立于要比较的类。
这就是Compare()方法定义了两个要比较的变元的原因。
其返回值与IComparable接口的CompareTo()方法类似。
类PersonComparer实现了IComparer接口,可以按照firstName或lastName对Person对象排序。
枚举PersonCompareType定义了与PersonComparer相当的排序选项:
FirstName和LastName。
排序的方式由类PersonComparer的构造函数定义,在该构造函数中设置了一个PersonCompareType值。
Compare()方法用一个switch语句指定是按firstName还是lastName排序。
publicclassPersonComparer:
IComparer
{
publicenumPersonCompareType
{
FirstName,
LastName
}
privatePersonCompareTypecompareType;
publicPersonComparer(PersonCompareTypecompareType)
{
this.compareType=compareType;
}
publicintCompare(objectx,objecty)
{
Personp1=xasPerson;
Personp1=yasPerson;
Switch(compareType)
{
casePersonCompareType.FirstName:
returnp1.FirstName.CompareTo(p2.FirstName);
casePersonCompareType.LastName:
returnp1.LastName.CompareTo(p2.LastName);
default:
thrownewArgumentException("unexpextedcomparetype")
}
}
}
现在,可以将一个PersonComparer对象传送给Array.Sort()方法的第二个变元。
下面是按名字对persons数组排序:
Array.Sort(persons,
newPersonComparer(PersonComparer.PersonCompareType.FirstName));
foreach(Personpinpersons)
{
Console.WriteLine(p);
}
persons数组现在按名字排序:
AyrtonSenna
EmersonFittipaldi
MichaelSchumacher
NikiLauda
提示:
Array类还提供了Sort方法,它需要将一个委托作为变元。
第7章将介绍如何使用委托。