有以下现象:
cs
public class Chinese
{
public string Name { get; set; }
public int Age { get; set; }
public int Height { get; }
}
cs
var chiPersons = new List<Chinese>
{
new Chinese { Name = "张三", Age = 25 },
new Chinese { Name = "李四", Age = 30 },
new Chinese { Name = "王五", Age = 28 }
};
//创建新链表,使用存在的chiPersons 填充
ObservableCollection<Chinese> MachinePositionList = new ObservableCollection<Chinese>(chiPersons);
MachinePositionList[0].Age = 100;
//chiPersons 第一个元素会跟随更改
var a = chiPersons[0].Age;
//看到chiPersons 第一个元素的Age也变成了100,
//我天真的以为两个链表的内存地址是一致的
var newPerson = new Chinese { Name = "麻子" };
//向新链表中添加元素
MachinePositionList.Add(newPerson);
//原链表长度不变
var count = chiPersons.Count;
//同理,删除新链表的元素,原链表长度也不变
var zhangSan = MachinePositionList[0];
MachinePositionList.Remove(zhangSan);
count = chiPersons.Count;
1. 内存结构图
栈内存 堆内存
─────────────────────────────────────────────────────
chiPersons变量 ──→ List<Chinese> 对象
├─ 数组(元素是引用)
├─ [0] ──→ Chinese对象A (张三,25)
├─ [1] ──→ Chinese对象B (李四,30)
└─ [2] ──→ Chinese对象C (王五,28)
MachinePositionList变量 ──→ ObservableCollection<Chinese> 对象
├─ 内部容器(元素是引用)
├─ [0] ──→ 同上Chinese对象A ⬅ 共享!
├─ [1] ──→ 同上Chinese对象B ⬅ 共享!
└─ [2] ──→ 同上Chinese对象C ⬅ 共享!
2. 关键内存行为
① 构造函数填充(浅拷贝)
csharp
new ObservableCollection<Chinese>(chiPersons)
-
只复制了引用 (指针),没有复制
Chinese对象本身 -
两个集合的每个槽位指向堆上同一组
Chinese对象
② 修改元素属性
csharp
MachinePositionList[0].Age = 100;
-
通过
MachinePositionList[0]拿到引用,顺着指针找到堆上的Chinese对象 A -
修改其
Age字段 -
chiPersons[0].Age也变成 100(因为是同一个对象)
③ 添加新元素
csharp
MachinePositionList.Add(newPerson);
-
newPerson指向新创建的Chinese对象 D(麻子) -
ObservableCollection在自己的内部数组末尾添加这个新引用 -
List<Chinese>的内部数组长度不变(仍为 3) -
两个集合从此独立:各自维护自己的引用数组
3. 内存变化时序
| 操作 | chiPersons内部数组 | MachinePositionList内部数组 | 堆上对象 |
|---|---|---|---|
| 初始化 | refA, refB, refC | refA, refB, refC | A, B, C |
| 修改Age | refA, refB, refC | refA, refB, refC | A(age=100), B, C |
| Add新元素 | refA, refB, refC | refA, refB, refC, refD | A, B, C, D |