CLR via C#学习笔记-第十六章-数组
第16章 数组
数组在内存中的情况
CLR支持一位、多维、交错数组。所有数组都隐式从System.Array,后者又派生自System.Object。
这意味着数组始终是引用类型,是在托管堆上分配的。
应用程序中的字段或变量中,包含的是对数组的引用,而不是包含数组本身的元素。
值类型数组
int[] myIntegers; myIntegers=new int[100];
第一行代码声明遍历,它指向包含int值的一维数组,一开始被设为null,第二行分配了含有00个int值的数组,所有int都被初始化为0。
由于数组是引用类型,所以会在托管堆上分配容纳100个未装修int所需的内存块。
除了数组元素,数组对象占据的内存块还包含一个类型对象指针、一个同步块索引和一些额外成员。该数组的内存块地址被返回并保存到myIntegers变量中。
引用类型数组
还可以创建引用类型的数组:
Control[] myControls; myControls=new Control[50];
第一行代码声明变量,一开始被设为null,第二行分配了50个Control引用的数组,这些引用全被初始化为null。这个内存块的地址被返回并保存到myControl变量中
数组的种类
一维零基数组,又称向量。
多维数组
交错数组
数组的初始化
使用new
C#允许一个语句创建数组对象并初始化数组中的元素。
String[] names=new String[]{"A","B"};
大括号中的逗号分隔的数据项称为数组初始化器。
每个数据项否可以是任意复杂度的表达式。
利用C#的隐式类型的局部变量简化
var names=new String[]{"A","B"};
利用隐式类型的数组功能让编译器自己推断数组元素的类型
var names=new[] {"A","B",null};
由于null可以隐式转换位任意引用类型,所以上述代码中编译器能推断出类型String。
初始化数组时的额外语法奖励
String[] names={"A","B"};
编译器不允许这种语法中使用隐式类型的局部变量
var names={"A","B"};//错误
隐式类型的数组与匿名类型和隐式类型的局部变量结合使用
var kids=new[] {new{Name="A"},new {Name="Grant"}}; foreach(var kid in kids) Console.WriteLine(kid.Name);
数组转型
CLR允许将数组元素从一种类型转型另一种。
要求数组维度相同,必须存在从元素源类型到目标类型的隐式或显式转换。
CLR不允许将值类型元素的数组转型为其他任何类型。
Copy方法
不过可以用Array.Copy方法创建新数组并在其中填充元素来模拟这种效果。
Copy方法还能在复制每个数组元素时进行必要的类型转换
①将值类型元素装箱成引用类型,比如将int[]复制到Object[]
②将装箱值类型拆箱成未装箱值类型,比如将Object[]拆箱为int[]
③加宽基元类型,int[]赋值到double[]
所有数组都隐式派生自System.Array
FileStream[] fsArray;
CLR会自动为AppDomain创建一个FIleStream[]类型。该类型隐式派生自System.Array。
因此Array类型定义的所有实例方法和属性都将由FileStream[]继承。
数组的传递和返回
数组作为实参返回给方法时,实际传递的是对该数组的引用。
如果不想被修改,必须将生成数组的拷贝并将拷贝传给方法。
Array.Copy方法执行的是浅拷贝,换言之,如果数组元素是引用类型,新数组将引用现有对象。
如果定义返回数组引用的方法,而且数组不包含元素,方法既可以返回null也可以返回对包含零个元素的一个数组的引用。
微软建议返回后者,这样能简化调用该方法时需要写的方法。否则就要先判断数组是否为null。
创建下限非零的数组
调用数组的静态CreatInstance方法动态创建自己的数组,允许指定数组元素的类型、数组的维度、每一维的下线和每一维的元素数目。
CreateInstance为数组分配内存,将参数信息保存到数组的内存块的开销部分,然后返回对该数组的引用。
数组的内部工作原理
CLR'内部支持两种不同的数组
①下限为0的一维数组,一维0基数组或向量
②下线未知的一位或多维数组
运行时,CLR将所有多维数组都视为非0基数组。但只有一维非0基数组显示为String[*]。
CLR访问非0基数组或多维数组比一维0基数组慢。