数组

数组

一:简单数组                                                                

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

1.1:数组的声明:
在声明数组时,应先定义数组中元素的类型。其后是一对空方括号和一个变量名。例如:下面声明了一个包含整型元素的数组:

 

            int[] MyArray;

 

1.2:数组的初始化:

声明了数组之后,就必须为整组分配内存,以保存数组中的所有的元素。数组是引用类型,所以必须给它分配堆上的内存。为此,应使用new运算符,指定数组中元素的类型和数量来初始化数组的变量。下面定义了数组的大小:

 

            int[] MyArray = new int[4];

 


在声明和初始化数组之后,变量MyArray就引用了4个整数值,它们位于托管堆上,如图表示:

注意:在指定了数组的大小之后,如果不复制数组中的所有的元素,就不能重新设置数组中大小,如果事先不知道数组中应包含多少个元素,就可以使用集合。

除了在两个语句中声明和初始化数组之外,还可以在一个语句中声明和初始化数组。

            int[] myArray = new int[4];

还可以使用数组初始化器为数组中的每个元素赋值。数组初始化器只能在声明数组变量时使用,不能再声明数组之后使用。

            int[] myArray = new int[4] { 1, 2, 3, 4 };

如果用花括号初始化数组,则还可以不指定数组的大小。因为编译器会自动的帮助我们统计元素的个数。

            int[] myArray = new int[] { 1, 2, 3, 4 };

使用c#编译器还有一种更加简化的形式,使用花括号可以同时声明数组和初始化数组。编译器生成的代码与前面的例子相同:

            int[] myArray = { 1, 2, 3, 4 };

1.3:访问数组中的元素:

在声明和初始化数组后,就可以使用索引器访问其中的元素了。数组之只支持有整型参数的索引器。通过索引器传递元素的编号,就可以访问数组。索引器总是以0开头。表示第一个元素。可以传递给索引器的最大值是元素的个数减一。在下面的例子中,数组myArray用4个整型值声明和初始化。用索引器对应的值是0、1、2、3就可以访问数组中的元素了。

 

        static void Main(string[] args)
        {
            int[] myArray = { 1, 2, 3, 4 };
            int num1 = myArray[0];              //第一个值
            int num2 = myArray[1];              //第二个值      
            int num3 = myArray[2];              //第三个值      
            int num4 = myArray[3];              //第四个值
            myArray[3] = 5;                     //改变其中的值
            Console.WriteLine(num1);
            Console.WriteLine(num2);
            Console.WriteLine(num3);
            Console.WriteLine(num4);
            Console.ReadKey();
        }


如果使用错误的索引器(大于数组的长度),就会抛出异常。

如果不知道数组中的元素的个数,则可以在for语句中使用Length属性。

            for (int i = 0; i < myArray.Length; i++)
            {
                Console.WriteLine(myArray[i]);
            }

 

除了使用for语句迭代数组中的所有的元素之外,还可以使用foreach语句(在后面讨论IEnumerable和IEnumerator接口):

 

            foreach (var myArray in myArrays)
            {
                Console.WriteLine(myArray);
            }

 1.4:使用引用类型:

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

 

    public class Person
    {

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public override string ToString()
        {
            return string.Format("{0},{1}", this.FirstName, this.LastName);
        }

    }

 

 

声明一个包含两个Person元素中的数组与声明一个int数组类似:

 

            Person[] myPersons = new Person[2];

 


但是必须注意:如果数组中的元素是引用类型,就必须为每个数组元素分配内存。若使用了数组中未分配了内存的元素,就会抛出异常。

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

            myPersons[0] = new Person { FirstName = "", LastName = "" };
            myPersons[1] = new Person { FirstName = "", LastName = "" };

如下图显示了Person数组中的对象在托管堆中的情况。myPersons是存储在栈上的一个变量。该变量引用了存储在托管堆上的Person元素对应的数组。这个数组有足够容纳两个引用的空间。数组中的每一项都引用了一个Person对象。而这些Person对象也存储在托管堆上。

与int类型一样,也可以对自定义类型使用数组初始化器:

 

            Person[] myPersons = { new Person { FirstName = "", LastName = "" }, new Person { FirstName = "", LastName = "" } };

 

二:多维数组                                                        

一般数组(一维数组)用一个整数来索引。多维数组用两个或者多个整数来索引。如下图,是二维数组的数学表示法,该数组有3行3列,第一行的值是1,2,3,第三行的值是7,8,9。

在c#中声明一个二维数组,需要在方括号中加上一个逗号,数组在初始化时应指定每一维的大小(也称为阶)。接着,就可以使用两个整数作为索引器来访问数组中的元素了。

        static void Main(string[] args)
        {
            int[,] twoim = new int[3, 3];
            twoim[0, 0] = 1;
            twoim[0, 1] = 2;
            twoim[0, 2] = 3;
            twoim[1, 0] = 4;
            twoim[1, 1] = 5;
            twoim[1, 2] = 6;
            twoim[2, 0] = 7;
            twoim[2, 1] = 8;
            twoim[2, 2] = 9;
        }

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

如果事先知道元素的值,则也可以使用数字索引器来初始化二维数组。在初始化数组时,使用一个外层的花括号,每一行用包含在外层花括号中的内层花括号来初始化。

            int[,] twoim =
            {
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9}
            };

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

三:Array数组                                                          

用方括号声明数组是c#中使用的Array类的表示法。在后台使用c#语法。会创建一个派生子抽象基类Array的新类。这样,就可以使用Array类为每个c#数组定义的方法和属性了。例如前面就使用了Length属性。或者使用foreach语句迭代数组。其实是使用了Array类的GetEnumerator()方法。

3.1:创建数组:

Array类是一个抽象类,所以不能使用构造函数来创建数组。但是除了可以使用c#语法创建数组实例之外,还可以使用静态方法CreatInstance()创建数组。如果事先不知道元素的类型。该静态方法就非常的有用。因为类型可以作为Type对象传递给CreatInstance()方法。

下面我们创建一个类型为int、大小为5的数组。CreatInstance()的第一个参数就是元素的类型。第二个参数是定义数组的大小。可以用SetValue()方法设置对应元素的值。用GetValue()读取定义元素的值。

 

        static void Main(string[] args)
        {
            Array intArray = Array.CreateInstance(typeof(int), 5);
            for (int i = 0; i < 5; i++)
            {
                //值的设置
                intArray.SetValue(33, i);
            }
            for (int i = 0; i < 5; i++)
            {
                //获取数组中的值
                Console.WriteLine(intArray.GetValue(i));
            }
            Console.ReadKey();
        }

 


还可以将已创建的数组强制转换成声明为int[]的数组。

            int[] intArray2 = (int[]) intArray;

3.2:数组的复制:

因为数组是引用类型,所以将一个数组变量赋予另一个数组变量。就会得到两个引用同一个数组的变量。而赋值数组,会使数组实现ICloneable接口。这个接口定义的Clone()方法会创建数组的浅表副本。

如果数组中的元素是值类型,以下代码段就会复制所有的值,如图所示:

 

            int[] intArrays = { 1, 2 };
            int[] intArrays_2 = (int[])intArrays.Clone();

 

 

如果数组中包含引用类型,则不是复制元素,而是只复制引用。beatles和beatlesClone引用的Person是相同的。如果修改beatles中的一个元素,就会改变beatles中对应对象。

 

            Person[] beatles = { new Person { FirstName = "", LastName = "" }, new Person { FirstName = "", LastName = "" } };
            Person[] beatlesClone = (Person[])beatles.Clone();

 

 

除了使用Clone()方法之外,还可以使用Array.Copy()方法创建浅表副本。但是Clone()和Copy()方法有一个重要的区别:Clone()方法会创建一个新数组,而Copy()方法必须传递阶数相同且有足够元素的已有数组。

3.3:排序:

Array类使用QuickSort算法对数组中的元素进行排序。Sort()方法需要数组中的元素实现IComparable接口。因为简单类型实现IComparable接口。所以可以对包含这些类型的元素排序。

我们首先来看一个数组:

 

        static void Main(string[] args)
        {
            string[] names = { "Christina Aguilera", "Ahakira", "Beyonce", "Dady Gaga" };
            //进行排序
            Array.Sort(names);
            //数组中元素的反转
            Array.Reverse(names);
            foreach (string name in names)
            {
                Console.WriteLine(name);
            }
            Console.ReadKey();
        }

 

 

:枚举                                                        

在foreach语句中使用枚举,可以迭代集合中的元素,且无需知道集合中的元素个数。foreach语句使用了一个枚举器。数组或者集合首先带GetEnmerator()方法的IEumerable接口。GetEumerator()方法返回一个实现IEumerable接口的枚举。接着foreach语句就可以使用IEumerable接口迭代集合了。

foreach 语句使用IEnumerator接口的方法和属性,迭代集合中的所有的元素。为此,IEnumerator定义了Current属性,来返回光标所在的元素。该接口的MoveNext()方法移动到集合的下一个元素上,如果有这个元素,该方法就返回true。如果集合中不在有更多的元素,该方法就返回false。

c#的foreach语句不会解析为IL代码中的foreach语句。c#编译器会把foreach语句转换为IEnumerable接口中的方法和属性。下面是一条简单的foreach语句。它迭代names数组中的所有的元素。

 

            string[] names = { "Christina Aguilera", "Ahakira", "Beyonce", "Dady Gaga" };

 

            foreach (string name in names)
            {
                Console.WriteLine(name);
            }

4.1:yield 语句

使用foreach语句可以轻松的迭代集合。c#2.0添加了yield语句。以便于创建枚举器。yield return 语句返回集合的一个元素,并移动到下一个元素中。yield break 可停止迭代。

        public IEnumerable<string> GetEnumerator()
        {
            yield return "Hello";
            yield return "World";
        }

包含yield语句的方法或者属性也称为迭代块。迭代块必须声明为返回IEnumerator或者IEnumerable接口。这个块中可以包含多条yield return语句或者yield break语句。但是不能包含return 语句。

现在可以迭代foreach语句迭代集合了:

        public void HelloWorld()
        {
            var helloCollection = new HelloCollection();
            foreach (var s in helloCollection)
            {
                Console.WriteLine(s);
            }
        }
posted @ 2017-11-13 19:55  丢了蜡笔小新会哭〆  阅读(289)  评论(0编辑  收藏  举报