1、简单数组
1、数组声明:
- 先定义数组中元素的类型,
- 其后是一对空方括号和一个变量名。
int[] myArray;
2、数组初始化:
- 声明了数组之后,必须为数组分配内存,以保存数组的所有元素。
- 数组是引用类型,必须分配堆上的内存,应使用new关键字。
myArray = new int[4]
- 可以在一个语句中声明和初始化数组
int[] myArray = new int[4];
使用初始化器为数组赋值,如果用花括号初始化数组,可以不指定数组的大小,编译器会自动统计。
int[] myArray = new int[4]{2,4,1,3}; int[] myArray = new int[]{2,4,1,3};
更简单的方式,使用花括号可以同时声明和初始化数组;
int[] myArray = {4,2,6,1};
- 3、访问数组元素
- 使用索引器访问其中的元素。
- 数组只支持有整型参数的索引器,索引器总是以”0”开头的。
- 4、使用引用类型
- 除了能声明预定义类型的数组,还可以声明自定义类型的数组。
public calss Person { public string FirstName{get;set;} public string LastName{get;set;} public override string ToString() { return String.ForMat("{0} {1}", FirstName, LastName); } } //声明一个包含两个Person元素的数组 Person[] MyPersons = new Person[2]; myPerson[0] = new Person{FirstName="a", LastName="b"};
2、多维数组
- 用两个或多个整数来索引。
- 需要在方括号中加上一个逗号。
int[,] twodim = new int[3,3]; //初始化一个二维数组
3、锯齿数组
锯齿数组的大小设置比较灵活,每一行都可以有不同的大小。
- 在声明锯齿数组时,要依次放置左右括号。
- 在初始化锯齿数组时,只在第1对方括号中设置该数组包含的行数之后,为每一行指定行中的元素个数。
int [][] jagged = new int[3][]; jagged = new int[2]{2,1}; jagged = new int[6]{3,5,2,4,6,8}; jagged = new int[3]{3,6,8};
4、Array类
- 用方括号声明数组是C#中使用Array类的表示法。
- 在后台使用C#语法,会创建一个派生自抽象基类Array的新类。
Array类的属性:
- LongLength:获得元素个数(元素个数超出了整数的取值范围),一般情况,使用Length;
- Rank:获得数组的维数;
5、使用Array类创建数组
- Array类是一个抽象类,不能使用构造函数来创建数组,要使用静态方法
CreateInstance()
创建数组。- 方法的第一个参数是元素类型,第二个参数定义数组的大小。
可以用SetValue()设置对应元素的值,用GetValue()读取对应元素的值。
Array myArray = Array.CreateInstance(typeof(int), 4); //创建类型为int、大小为4的数组 for (int i = 0; i < 4; i++) { myArray.SetValue(22, i); } for (int i = 0; i < 4; i++) { Console.WriteLine(myArray.GetValue(i)); }
CreateInstance()
方法可以许多重载版本,可以创建多维数组和不基于0的数组。
int[] lengths = {2,3}; //创建一个包含2x3的二维数组 int[] lowerBounds = {1,10}; //第一维基于1,第二维基于10 Array racers = Array.CreateInstance(typeof(Person), lengths, lowerBounds); //创建数组 racers.SetValue(new Person { FirstName = "a"; LastName = "b"; }, 1,10); //赋值 //尽管数组不基于0,但可以将它赋予一个变量,只要不超过边界即可 Person[,] racersTemp = (Person[,])racers; Person first = racersTemp[1,10]; Person last = racersTemp[2,12];
6、复制数组:Clone()
- 数组会实现
ICloneable
接口,- 接口定义的Clone()方法会创建数组的浅表副本。
- 如果数组的元素是值类型,就只会复制所有的值;
- 如果数组包含了引用类型,则不复制元素,只复制引用。
int[] intArray1 = { 1, 3 }; //必须进行强制转换,Clone方法返回的是Objec对象 int[] intAyyay2 = (int[])intArray1.Clone();
7、Clone()与Copy()的区别
重要区别:
1. Clone方法会创建一个新的数组。
2. Copy方法必须传递阶数相同且有足够元素的已有数组。
8、数组排序
- Array类使用QuickSort算法对数组中的元素进行排序。
- Sort()方法需要数组中的元素实现IComparable接口。
- 简单类型已经实现了IComparable接口,所以可以直接排序;
- 如果数组使用自定义类,就必须实现IComparable接口,该接口只定义了一个方法CompareTo()。
- 注意:IComparer接口与IComparer接口,这两个接口定义了Compare()方法。
9、数组的协变
- 数组支持协变。表示数组可以声明为基类,其派生类型的元素可以赋予数组元素。
- 数组协变只能用于引用类型而且只能通过运行时异常来解决(ArrayTypeMismatchException)。
10、结构ArraySegment<T>
的作用
- 结构
ArraySegment<T>
表示数组的一段。- 在处理大型数组的不同部分时,我们将数组传递给不同的方法,这些方法只使用数组的某个部分。
ArraySegment<T>
结构包含了关于数组段的信息(偏移量和元素个数)。
// 定义SumOfSegment()方法 static int SumOfSegments(ArraySegment<int>[] segments) { int sum = 0; foreach (var segment in segments) { for (int i = segment.Offset; i < segment.Offset + segment.Count; i++) { sum += segment.Array[i]; } } return sum; } //使用SumOfSegment()求数组中部分值 int[] ar1 = { 1, 4, 6, 3, 7, 9, 0, 3 }; int[] ar2 = { 7, 3, 5, 78, 34, 12, 9, 4, 23, 2 }; var segments = new ArraySegment<int>[2] { new ArraySegment<int>(ar1,0,3), new ArraySegment<int>(ar2, 3, 3) }; var sum = SumOfSegments(segments); WriteLine(sum);
11、foreach语句
- C#编译器会把foreach语句转换为
IEnumerator
接口的方法和属性,迭代集合中的所有元素。IEnumerator
接口定义了Current属性,来返回光标所在元素。- 该接口的MoveNext()方法移动到集合的下一个元素,如果有这个元素,则返回true。
foreach(var p in persons) { WriteLine(p); } //等价于 IEnumerator<Person> enumerator = persons.GetEnumerator(); while(enumerator.MoveNext()) { Person p = enumerator.Current; WriteLine(p); }
12、yield语句(不理解)
- yield语句,便于创建枚举器。
- yield return语句返回集合的一个元素;
- yield break可以停止迭代。