一步一步学c#(六):数组

数组

简单数组

如果需要使用同一个类型的多个对象,就可以使用数组。数组是一种数据结构,它可以包含同一类型的多个元素。

数组声明:int[] myArray

使用new运算符,指定数组中元素的类型和数量来初始化数组的变量。指定数组的大小:

myArray=new int[4]

声明和初始化数组后,变量myArray就引用了4个整形值,它们位于托管堆上:

在一个语句中声明和初始化数组

int[] myArray=new int[4];

使用数组初始化器为数组的每个元素赋值。

int[] myArray=new int[4]{4,7,11,2};

访问数组元素

数组只支持有整型参数的索引器。索引器总是以0开始,表示第一个元素,可以传递给索引器的最大值是元素个数减1,因为索引从0开始。数组myArray用4个整型值声明和初始化。用索引器对应的值0,1,2,3就可以访问数组中的元素。

在for语句中使用Length属性,在不知道数组中的元素个数的情况下:

使用引用类型

除了能声明预定义类型的数组,还可以声明自定义类型的数组。用Person类来说明,这个类有自动实现的属性Firstname和Lastname.以及Object类重写的ToString()方法;

 

使用从0开始的索引器,可以为数组的每个元素分配内存:

下图显示了Person数组中的对象在托管堆中的情况。mypersons是储存在栈上的一个变量,该变量引用了储存在托管堆上的Pweson元素对应的数组。

多维数组

一般数组(也称为一维数组)用一个整数来索引,多维数组用两个或多个整数来索引。

二维数组的科学表示法:

声明数组之后,就不能修改其阶数了。

如果事先知道元素的值,则也可以使用数组索引器来初始化二维数组。

使用数组初始化时,必须初始化数组的每个元素,不能遗漏任何元素。

锯齿数组

二维数组

锯齿数组

在声明锯齿数组时,要依次放置左右括号。只在第一对括号中放置该数组包含的行数,定义各行中元素个数的第二个括号设置为空,因为这类数组的每一行包含不同的元素个数,之后,为每一个指定行中的元素个数:

迭代锯齿数组中所有元素的代码可以放在嵌套的for循环中。在外层的for循环中迭代每一行,在内层的for循环中迭代一行中的每个元素:

Array类

创建数组

Array类是一个抽象类,所以不能使用构造函数来创建数组。但除了可以使用c#语法创建数组实例之外,还可以使用静态方法CreateInstance()创建数组。

例子说明了如何创建类型int,大小为5的数组。

复制数组

因为数组是引用类型,所以将一个数组变量赋予另一个数组变量,就会得到两个引用同一数组的变量。而复制数组,会使数组实现IConeable。

如果数组包含引用类型,则不复制元素,而只复制引用。

显示变量beatles和beatlesClone,其中beatlesClone通过从beatles中调用Clone()方法创建。

Clone()方法和Copy()方法的区别:Clone()方法会创建一个新数组,而Copy()方法必须传递阶数相同且有足够元素的已有数组。

排序

Array类使用QuickSory算法对数组中元素的进行排序。

示例程序中,数组name包含string类型的元素,这个数组可以排序》

 

 

}

如果对数组使用自定义类。就必须实现IComparabe接口。此接口只定义了一个方法CompareTo(),如果要比较的对象相等,该方法就返回0.如果该实例应排在参数对象的前面,该方法就返回小于0的值,相反,就大于0的值。

LastName的值相同,就比较FirstName。

 

 

就可以按姓氏对Person对象对应的数组排列:

假如Person对象排序不同,就可以实现IComparer接口或IComparer<T>接口,定义Compare().IComparer接口独立于比较的类。

类PersonComparer实现了IComparer<Person>接口,按照firstName或lastName对Person对象排序。实现Compare()方法时用了一个switch语句指定是按FirstName还是LastName排序。

按名字对person数组排序:

数组作为参数

数组可以作为参数传递给方法。要返回数组,要将数组声明为返回类型。

GetPerson()所示:

 

数组协变

数组可以声明为基类,派生元素可以赋予数组元素。

声明object[]类型的参数,给它传递一个Perxon[]:

数组协变只能用于引用类型,不能用于值类型。

ArraySegment<T>表示数组的一段。如果某个方法只返回数组的一部份或给某方法传递数组的一部分,就可以用。

SumOfSegments<T>方法提取一组,ArraySegment<int>元素,计算数组定义的所有整数之和,并返回整数和:

使用这个方法时,传递一个数组段。第一个数组元素从ar1的第一个元素开始,引用了3个元素,第二个数组从ar2的第四个元素开始,引用3个元素:

枚举

在foreach语句中用枚举,可以迭代集合的元素,且无需知道集合中的元素个数。

下图显示了调用foreach方法的客户端和集合之间的关系。

foreach语句

首先foreach语句不会解析IL代码中的foreach语句。编译器会将它转换为IEnumerable借口的方法和属性。

foreach (var p in person)

{

       Console.WriteLine(p);

}

它迭代persons数组中的所有元素,并逐个显示。

foreach解析的代码段。

调用GetEnumerator()方法,获取数组枚举器。在While循环中——只要MoveNext()返回ture---就用Current属性访问数组中的元素。

yleld语句

用yiled retum语句实现一个简单集合的代码。

 

包含yield语句的方法或属性也称为迭代块。

用foreach语句迭代集合;

使用迭代块,编译器会生成一个yield类型,其中包含一个状态机。

 

yield类型实现IEnumerator和IDisposable接口的属性和方法。可以吧yield类型看做内部类Enumerator.  yield语句会生成一个枚举器,而不仅仅生成一个包含的项的列表。

迭代集合的不同方式

在下面的这个比hello Word示例略大但比较真实的示例中,可以使用yield return语句,以不同方式迭代集合的类。

类MUSICTitles可以用默认方式通过GetEnumerator()方法迭代标题,用Reverse()方法逆序迭代标题,用stubset()方法迭代子集。

默认使用的方法,迭代字符串数组的客户端代码先使用GetEnumerator()方法。

用yield retum返回枚举器

从yield return中返回枚举器。

 

在Tic Tac Top游戏中有9个域,玩家轮流在这些域中放置一个十字或一个圆。

使用Game Moves类。 第一次调用enumerator.MoveNext()时。会调用Cross()方法。

 

 元组

数组合并了相同类型的对象,而元组合并了不同的对象。

新建的元组用result和reminder变量初始化,返回这两个变量相除的结果:

下面代码说明了divide()方法的调用:

结构比较

IstructuralEquatable接口用于比较两个元素或数组是否有相同的内容,IstructuralComparable接口用于给元素或数组排序。

说明IstructuralEquatable接口的实例,使用实现IEquatable接口的Person类。

 

创建两个包含person项的数组。他们通过变量名Janet包含相同的person对象,和两个内容相同的不同person对象。

对于IstructuralEquatable接口定义的Equals()方法,第一个参数是object,第二个参数是IEqualityComparer类型。

person实现IEquatable<Person>,比较的对象的内容,数组确保含相同的内容:

 如何执行相同的操作:

Tuple<>提供了两个Equlas()方法:一个重写了object基类中的Equals()方法,并把object作为参数,第二个由IStructuralEqualityComparer接口定义,并把object和IEqualityComparer作为参数。

给第一个方法传送另一个元组。

 使用类TupleComparer创建一个自定义的IEqualityComparer.

 

posted @ 2014-09-21 15:59  【射天狼】  阅读(366)  评论(0编辑  收藏  举报