—— 值类型与引用类型的内存行为差异
🔍 一、数组协变(Array Covariance)
核心条件:
- 仅适用于引用类型数组
- 被赋值对象与数组基类型需存在隐式/显式转换关系
class Animal {}
class Dog : Animal {}Animal[] animals = new Dog[3]; // 合法协变:Dog[] 可赋值给 Animal[]
✅ 本质原因:
派生类(如Dog)可安全向上转型为基类(Animal),编译器允许此操作(图1演示内存布局):
⚠️ 重要限制:
int[] intArr = new long[3]; // 错误!值类型数组不支持协变
⚙️ 二、数组继承的核心成员
所有C#数组派生自System.Array,常用成员如下:
成员 | 作用 | 示例 |
---|---|---|
Length | 获取数组总元素数量 | arr.Length → 5 |
Rank | 获取数组维度 | arr.Rank → 1 (一维) |
GetLength(int) | 获取指定维度元素数量 | arr.GetLength(0) → 5 |
Sort() | 原地排序数组 | Array.Sort(arr) |
Reverse() | 反转数组元素顺序 | Array.Reverse(arr) |
Clone() | 浅复制(核心!见下文) | arr.Clone() |
⚠️ 三、Clone() 的浅复制行为
Clone() 仅复制数组容器本身,不递归复制元素对象,导致值类型与引用类型表现迥异:
▫️ 值类型数组克隆(独立副本)
int[] arr1 = { 1, 2, 3 };
int[] arr2 = (int[])arr1.Clone();arr2[0] = 100; // 修改不影响 arr1
✅ 内存结果:
→ 产生两个完全独立的数组
▫️ 引用类型数组克隆(共享对象)
class Item { public int Value; }
Item[] items1 = { new Item() };
Item[] items2 = (Item[])items1.Clone();items2[0].Value = 100; // 修改影响 items1[0]!
✅ 内存结果:
→ 两个数组指向同一组对象
💎 四、关键结论
- 协变安全性:仅引用类型数组支持协变,依赖继承链的隐式转换
- 克隆陷阱:
- 值类型数组克隆 → 完全独立副本
- 引用类型数组克隆 → 共享元素对象(需警惕副作用!)
- 操作规范:
- 修改克隆后的值类型数组安全无冲突
- 修改引用类型数组元素前,需深度复制元素对象(例如手动new实例)
行动提示:处理引用类型数组时,若需完全隔离数据,应实现深拷贝(如序列化/手动复制对象),而非依赖Clone()。