十六、数组(Arrays)

✅ 第16章:数组与集合(Arrays and Collections)


📘 一、数组初始化与类型系统

✅ 所有数组都是 System.Array 的子类

int[] nums = new int[] { 1, 2, 3 };
Console.WriteLine(nums.GetType()); // System.Int32[]
Console.WriteLine(nums is Array);  // true
  • 数组在 CLR 中是 一等对象,具有完整的元数据(类型、维度、大小)
  • 实现了 IEnumerableICollectionIList 接口(非泛型)

🧱 二、数组的装箱陷阱:协变性问题

string[] names = new string[3];
object[] objs = names; // ✅ 协变允许

objs[0] = 123; // ❌ 运行时抛出 ArrayTypeMismatchException

✅ C# 允许引用类型数组协变,但存在类型安全问题
➡️ 推荐:用泛型集合替代数组协变场景


🚀 三、数组与泛型集合对比

特性 数组 (T[]) List<T>
固定大小 ✅ 是 ❌ 自动扩展
速度 ✅ 极快 稍慢,带边界检查
安全性 ✅ 高 ✅(泛型安全)
动态增删 ❌ 不支持 ✅ 支持

结论:数组适合底层高性能密集数据场景;集合适合动态操作


📌 四、数组作为参数传递与返回

  • 数组是引用类型:传递的是引用地址(但不会修改引用本身)
void Fill(int[] arr) {
    arr[0] = 100;       // ✅ 修改内容
    arr = new int[5];   // ❌ 不影响原数组
}

🔁 五、数组转型与接口转换

int[] arr = {1,2,3};
IEnumerable<int> seq = arr;   // ✅ 支持
IList list = arr;             // ✅ 支持非泛型接口

➡️ 因为 System.Array 实现了很多接口,易于与 LINQ、foreach 兼容


🌐 六、非零下限数组(不推荐使用)

Array arr = Array.CreateInstance(typeof(int), new int[] { 3 }, new int[] { 1 });

创建下限为 1 的数组 [1,2,3],但不兼容大部分 C# 语法与优化。

➡️ ⚠️ 性能差、兼容性差,不建议在实际项目中使用


🧠 七、数组内部工作机制(CLR视角)

✅ 数组头部结构(内存布局):

+-------------------------+
| Method Table Ptr        | ← 类型元数据
| Length (Int32)          | ← 数组元素数量
| [Element 0]             |
| [Element 1]             |
| ...                     |
+-------------------------+
  • 元数据指向类型信息(类型名、元素类型)
  • 紧跟数组长度字段(避免越界)
  • 然后是连续元素块

⚙️ 八、不安全数组访问与固定大小数组

unsafe {
    fixed (int* p = myArray) {
        *(p + 1) = 42;
    }
}
  • fixed 禁止 GC 移动数组
  • 可用于原生交互 / 性能极端优化(如图像处理)

📊 Mermaid 图:数组行为概览

graph LR A[定义数组] --> B[引用类型 System.Array] B --> C[实现 IEnumerable/IList] C --> D[传递到方法中] B --> E[存储元素 + 长度] E --> F[支持协变(仅引用类型)]


🧪 面试题


1️⃣ 为什么数组协变会导致运行时异常?

✅ 因为可以将 string[] 赋值给 object[],但 object[] 允许写入任何类型,破坏类型安全。


2️⃣ 创建数组后能改变其大小吗?

❌ 不可以。数组大小固定,只能重新创建新数组并复制内容。


3️⃣ 多维数组 vs 交错数组(区别?)

  • 多维数组是 [,],内存连续,占用空间大
  • 交错数组是 [][],每行可不同长,更灵活、兼容

4️⃣ 为什么数组不能作为协变泛型?

✅ 协变泛型需要只读行为,数组是可变集合,不满足约束。


5️⃣ 使用 Array.Copy()Buffer.BlockCopy() 有何不同?

Array.Copy() 是类型安全的;BlockCopy() 是字节级别的,适合低层数据处理(比如结构体序列化)


九、BlockCopy和Span

[[BlockCopy]]

✅ 总结速查表

特性 说明
是引用类型 数组存储在堆上,参数传递为引用
支持协变 仅限引用类型,存在类型风险
多接口支持 可转为 IEnumerable, IList 等
多维 vs 交错 多维占内存、慢;交错灵活
不安全访问 用于极限性能优化场景
非零下限 支持,但不推荐使用
posted @ 2025-08-26 10:06  世纪末の魔术师  阅读(10)  评论(0)    收藏  举报