C#学习笔记(七)—–集合--Array

来源:互联网 发布:加工中心简单编程实例 编辑:程序博客网 时间:2024/06/15 10:00

集合–Array

Array类是所有一维数组和多维数组的基类。而且它是实现集合接口中最基本的类型之一。Array提供了类型统一性,所以常见的方法都适用于Array,而与他们声明地实际类型无关。
当使用C#语法创建一个数组时,CLR会在内部将它转化为Array的子类–合成一个对应该数组维数和元素类型的类型。这个类型实现了已经闭合的泛型IList,例如:IList<string>
CLR也会特别处理数组类型的创建,将他放在一个连续内存空间,因此索引的效率非常高,但是不允许在创建后改变数组。
Array实现了IList的泛型和非泛型接口,但是,泛型的IList是显示实现的,以保证Array的公共接口上面没有Add和Remove方法,这些方法在固定长度的数组上操作是没有任何意义的。Array类的实例也提供一个Resize方法,本质上是创建了一个数组的新实例,但这个方式是低效的。创建一个可变长度的集合的最好的方法是使用List<T>类。
数组可以包含数值类型的也可以包含引用类型的,数值类型的存储在数组中(占用的是连续的内存空间),所以一个有三个long整数的数组占24个字节的空间。然而,引用类型在数组中存放只占用一个引用所需要的空间(32为系统的是4字节,64位的是8字节)。看下图:

StringBuilder[] builders = new StringBuilder [5];builders [0] = new StringBuilder ("builder1");builders [1] = new StringBuilder ("builder2");builders [2] = new StringBuilder ("builder3");long[] numbers = new long [3];numbers [0] = 12345;numbers [1] = 54321;

这里写图片描述
Array是一个类,所以不管上面存储的值类型还是引用类型,数组本身是引用类型。这以为这arrayA=arrayB是将两个变量指向了同一个数组对象。类似的,两个不同的数组在等值比较中总是不相等的—-除非自定义一个等值比较。Framework4.0后提供了一种用于比较数组或元组元素比较方式,通过StructuralComparisons类进行访问:

object[] a1 = { "string", 123, true };object[] a2 = { "string", 123, true };Console.WriteLine (a1 == a2); // FalseConsole.WriteLine (a1.Equals (a2)); // FalseIStructuralEquatable se1 = a1;Console.WriteLine (se1.Equals (a2,StructuralComparisons.StructuralEqualityComparer)); // True

数组可以通过Clone方法进行复制:arrayA=arrayB.Clone();然而,这是一个浅复制,只有数组本身表示的内存会被复制。如果数组包含的是值类型的对象,那么这些值会被复制,如果数组包含的是引用类型的对象,那么只有引用类型本身被复制(结果就是两个数组变量指向了同一个数组对象)。

StringBuilder[] builders2 = builders;StringBuilder[] shallowClone = (StringBuilder[]) builders.Clone();

这里写图片描述
如果要进行深度赋值即复制数组中的每一个对象,就要遍历数组,然后手动的复制。相同的规则也适用于其它集合类型。

Array主要是针对32为索引设计的,但是它也能够通过一些方法实现对64位索引的支持,但是在理论上数组最多能存2的64次方个元素,CLR不允许有任何对象能够超过2G的大小。所以这些重载方法其实用的非常少。
Array上的很多方法你期望是实例方法,实际上是静态的方法,这是一个古怪的设计决策,所以当你找一个数组的方法时,你即要查看他的实例方法,也要查看他的静态方法。

构造和索引

最简单的构造和索引数组的方式是使用C#的语言构造:

int[] myArray = { 1, 2, 3 };int first = myArray [0];int last = myArray [myArray.Length - 1];

也可以通过Array.CreateInstance();来在创建一个。这允许你动态的创建一个数组—–在运行时指定元素类型和数组大小。也允许为非零开始索引的数组指定下界,非零开始索引的数组在CTS中是不允许的。(这句特么有点弄不明白意思了,明白的同学帮我看一下,留个言,这里是StackOverFlow上面的回答:https://stackoverflow.com/questions/955732/c-nonzero-based-arrays-are-not-cls-compliant)
静态的GetValue和SetValue方法可以让你在一个动态创建的数组中处理元素。它们在普通数组上也可以工作。

// 创建一个长度为2的数组Array a = Array.CreateInstance (typeof(string), 2);a.SetValue ("hi", 0); // → a[0] = "hi";a.SetValue ("there", 1); // → a[1] = "there";string s = (string) a.GetValue (0); // → s = a[0];// 我们也可以通过下面的方式转换为一个C#数组string[] cSharpArray = (string[]) a;string s2 = cSharpArray [0];

动态创建的从零开始索引的数组可以安全的转换为一种类型匹配或兼容的C#数组,例如,如果apple是fruit的子类,可以fruit[]=apple[];这就产生一个问题,为什么不用object类,要用Array呢?原因就是object数组既不兼容多维数组也不兼容值类型数组以及非零开始索引的数组。int[]不能转换为object[]。因此我们需要Array来实现类型的统一性。
GetValue和SetValue方法也支持操作从编译器创建的数组。并且它们对于编写能够操作任意类型和任意维数的数组是很有帮助的。对于多维数组,它们接收一个索引器的数组:

public object GetValue (params int[] indices)public void SetValue (object value, params int[] indices)

当实例化数组时,无论是通过语言语法还是Array.CreatInstance,数组元素都会进行初始化。对于引用类型的数组,这意味着每个元素被初始化为null,对于值类型元素的数组,意味着要调用值类型的默认构造函数(有效的进行归零操作)。Array类也通过Clear方法实现归零功能。

public static void Clear (Array array, int index, int length);

这种方法不会改变元素的大小。

枚举

数组可以通过foreach语句进行枚举:

int[] myArray = { 1, 2, 3};foreach (int val in myArray)Console.WriteLine (val);

也可以使用静态的Array.ForEach方法进行枚举,如下所示:

public static void ForEach<T> (T[] array, Action<T> action);

这种方法使用一个Action的委托:

public delegate void Action<T> (T obj);

下面使用Array.ForEach重写的一个例子:

Array.ForEach (new[] { 1, 2, 3 }, Console.WriteLine);

长度和维数

Array提供了下面的方法和属性来查询长度和维数:

public int GetLength (int dimension);public long GetLongLength (int dimension);public int Length { get; }public long LongLength { get; }public int GetLowerBound (int dimension);public int GetUpperBound (int dimension);public int Rank { get; } // Returns number of dimensions in array

①GetLength和GetLongLength会返回一个指定维度的长度(0表示一维数组),而Length和LongLength返回数组的元素总数(包括所有维数)。
②GetLoweBound和GetUpperBound在处理非零开始索引的数组时时很有用的。GetUpperBound返回的结果与任意维度的GetLowerBound和GetLength相加的结果是相同的。

查找

Array类提供了许多用于查找一位数组元素的方法:
BinarySearch方法:用于快速搜索排序数组中的特定元素

IndexOf/LastIndex方法:用于搜索未排序数组中的特定元素

Find/FindLast/FindIndex/FindLaseIndex/Find All/Exists/TrueForAll:用于搜索未排序数组中满足指定Predicate<T>的一个或多个元素.
如果结果值没有找到,这里的所有查找方法都不会抛出异常,而是返回一个整数-1。而返回泛型类型的方法则返回这个值得默认值(int是0,string是null)。

阅读全文
0 0
原创粉丝点击