CLR via C# 笔记 -- 数组(16)
1. 数组隐式继承 System.Array,所以数组是引用类型。变量包含的是对数组的引用,而不是包含数据本身的元素。
2. 数组协变性。将数组从一种类型转换为另一种类型。
string[] sa = new string[100]; object[] oa = sa; oa[5] = "Jeff"; // 性能损失:CLR检查oa的元素类型是不是String;检查通过 oa[3] = 5; // 性能损失:CLR检查oa的元素类型是不是Int32;发现有错,抛异常
System.Buffer的BlockCopy方法,只支持基元类型,不具有转型能力。
System.Array的ConstrainedCopy方法,要么完美复制,要么抛出异常,不会破坏目标数组中的数据,不执行装箱、拆箱和向下类型转换。
3. 所有数组都隐式实现 IEnumerable,ICollection,IList
4. 创建下限非0的数组
int[] lowerBounds = { 2015, 1 }; int[] lengths = { 5, 4 }; decimal[,] quarterlyRevenue = (decimal[,])Array.CreateInstance(typeof(decimal), lengths, lowerBounds); Console.WriteLine("{0,4} {1,9} {2,9} {3,9} {4,9}", "year", "Q1", "Q2", "Q3", "Q4"); int fristYear = quarterlyRevenue.GetLowerBound(0); // 2015 int lastYear = quarterlyRevenue.GetUpperBound(0); // 2019 int fristQuarter = quarterlyRevenue.GetLowerBound(1); // 1 int lastQuarter = quarterlyRevenue.GetUpperBound(1); // 4 for (int year = fristYear; year <= lastYear; year++) { Console.Write(year + " "); for (int quarter = fristQuarter; quarter < lastQuarter; quarter++) { Console.Write("{0,9:C} ", quarterlyRevenue[year, quarter]); } Console.WriteLine(); }
5. 数组只有两种,下限为0的一维数组(System.String[])和下限未知的多维数组(System.String[,])。1维1基数组(System.String[*])C#不允许使用。访问一维0基数组比访问非0基多维数组要快,因为在for循环中JIT编译器会生成代码来检查是否 0 >= GetLowerBound(0) && (length-1) <= GetUpperBound(0),一维0基数组只会在for循环前检查1次,非0基多维数组则每次都会检查。
private const int c_numElements = 10000; public static void Main() { int[,] a2Dim = new int[c_numElements, c_numElements]; int[][] aJagged = new int[c_numElements][]; for (int x = 0; x < c_numElements; x++) { aJagged[x] = new int[c_numElements]; } Safe2DimArrayAccess(a2Dim); SafeJaggedArrayAccess(aJagged); Unsafe2DimArrayAccess(a2Dim); } private static int Safe2DimArrayAccess(int[,] a) { int sum = 0; for (int x = 0; x < c_numElements; x++) { for (int y = 0; y < c_numElements; y++) { sum += a[x, y]; } } return sum; } private static int SafeJaggedArrayAccess(int[][] a) { int sum = 0; for (int x = 0; x < c_numElements; x++) { for (int y = 0; y < c_numElements; y++) { sum += a[x][y]; } } return sum; } private static unsafe int Unsafe2DimArrayAccess(int[,] a) { int sum = 0; fixed (Int32* pi = a) { for (int x = 0; x < c_numElements; x++) { int baseOfDim = x * c_numElements; for (int y = 0; y < c_numElements; y++) { sum += pi[baseOfDim + y]; } } } return sum; }
6. 栈上分配数组
public static void Main() { StackallocDemo(); InlineArrayDemo(); } private static void StackallocDemo() { unsafe { const int width = 20; Char* pc = stackalloc char[width]; // 在栈上分配数组 string s = "Jeffrey Richter"; for (int index = 0; index < width; index++) { pc[width - index - 1] = (index < s.Length) ? s[index] : '.'; } Console.WriteLine(new string(pc, 0, width)); } } private static void InlineArrayDemo() { unsafe { CharArray ca; Int32 widthInByBytes = sizeof(CharArray); Int32 width = widthInByBytes / 2; string s = "Jeffrey Richter"; for (int index = 0; index < width; index++) { ca.Characters[width - index - 1] = (index < s.Length) ? s[index] : '.'; } Console.WriteLine(new string(ca.Characters, 0 ,width)); } } internal unsafe struct CharArray { public fixed Char Characters[20]; }