• 数组


    数组

    一:简单数组                                                                

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

    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);
                }
            }
  • 相关阅读:
    (转).NET 多线程编程
    [WAP]WML学习笔记总结
    [计划]2010年1月的工作学习计划
    [计划]11月&12月学习与工作计划
    [HTTP]HTTP协议学习总结第一弹:RFC2616初读总结
    [培训总结]海量服务培训总结
    [随想]忙碌的2010
    Android电源管理
    Android 1.5: 飞行模式分析
    android JNI 调用
  • 原文地址:https://www.cnblogs.com/MoRanQianXiao/p/7825013.html
Copyright © 2020-2023  润新知