CLR Via C# 3rd 阅读摘要 -- Chapter 16 - Arrays
Initializing Array Elements
1. var names = new[] {"Aidan", "Grant", null}; 编译器正常编译,因为可以推断names是string[];
2. var names = new[] {"Aidan", "Grant", 123}; 编译器会产生编译错误;
3. var names = {"Aidan", "Grant"};编译器也会产生编译错误;
4. var kids = new[] {new {Name = "Aidan"}, new {Name = "Grant"}};这会生成匿名类型的数组。
Casting Arrays
1. Array.Copy可以从一个数组拷贝到另外一个数组,就像C的memmove。Copy还可以进行数组转换:
装箱值类型到引用类型,比如Int32[]到object[];
拆箱引用类型到值类型,比如object[]到Int32[];
拓宽原生类型,比如Int32[]到Double[];
降解元素,比如object[]到IFormattable[]。
2. System.Buffer.BlockCopy要比Array.Copy快的多,但是BlockCopy只支持原生类型;
3. System.Array.ConstrainedCopy提供可靠的数组拷贝操作,该方法可以用在CER(Constrained Execution Region)中,要求元数组和目的数组同类型;
4. 创建接口的数组,比如:IIterface[] interfaces = new IInterface[10];是可以的。
All Arrays Are Implicitly Derived from System.Array
1. 所有的数组隐式的从System.Array继承。
All Arrays Implicitly Implement IEnumerable, ICollection, and IList
1. 所有的数组隐式的实现了IEnumerable,ICollection,IList接口;
2. CLR没有给System.Array实现IEnumerable<T>, ICollection<T>, IList<T>泛型接口,但是当一个一维零基的数组类型建立时,CLR自动标记这个数组类型实现这三个泛型接口,并且实现了该数组类型的所有基类型(引用类型)的这三个泛型接口;
3. 如果是值类型,CLR只实现该类型的IEnumerable<T>, ICollection<T>, IList<T>的泛型接口,而不实现基类型。
Passing and Returning Arrays
1. 当数组作为参数或者返回值时,传递的是引用。
Creating Non-Zero-Lower Bound Arrays
1. Array.CreateInstance(Type type, Int32[] lenths, Int32[] lowerBounds)可以创建一个非零基的多维数组;
2. Array.GetLowerBound()和Array.GetUpperBound()可以获得数组的上下边界。
Array Access Performance
1. 在循环中调用Array.Length成本比较高;
2. 访问非零基数组和多维数组要比一维的零基数组慢很多;
3. 数组的数组(jagged数组Int32[][])比规则的多维数组(Int32[,])要快;
4. unsafe的方式操作数组具有更高的性能和灵活性,但是要注意时机,下面三种情形要注意:
- 代码可读性复杂度增加,使用了fixed关键字并执行内存地址计算;
- 如果地址计算错误,那么会出现越界,产生安全隐患;
- CLR禁止不安全代码运行在受限环境下(比如SilverLight)。
Unsafe Array Access and Fixed-Size Array
1. 不安全数组的强大之处在于可以访问:
- 驻留在托管堆上的数组元素;
- 驻留在非托管堆上的数组元素;
- 驻留在线程栈上的数组元素。
2. 使用C#的stackalloc(类似与C的alloc)可以在线程栈上分配数组;
3. stackalloc可以用来创建一维零基的值类型数组。而且,大小有1M的限制。需要/unsafe编译开关;
4. 直接嵌入一个数组到结构体中需要满足几个条件:
- 类型必须是一个结构体(值类型);
- 字段和定义的结构体必须有unsafe关键字;
- 该结构体的数组字段必须有fixed关键字;
- 数组必须是一维零基的;
- 数组的元素类型必须是下列之一:Boolean, Char, Byte, SByte, Int32, UInt32, Int64, UInt64, Single, Double。
本章小结
本章讲述的是数组的概念。CLR可以支持多种形式的数组。首先讲了如何初始化一个数组,然后讲了如何转换数组以及Array.Copy的用途和局限性,阐明了数组的一些潜在特性,然后讲了如何创建一个多维非零基的数组,并且比较了不同数组在访问性能上的差异,最后重点解释了不安全数组的特性和使用要点。