C# 链表元素的引用地址分析

有以下现象:

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
相关推荐
samble10 小时前
从零搭建灌装监控系统(十七):LiveCharts 实时温度曲线
c#·wpf·mvvm·modbus·工业控制
0+11115 小时前
算法 --链表
数据结构·算法·leetcode·链表
淡海水19 小时前
02-07-原理篇-GC暂停时间的本质
开发语言·unity·c#·gc·暂停时间
小羊没烦恼!20 小时前
OS X 上使用.NET开发应用程序
开发语言·前端·数据库·人工智能·c#·策略模式
Behavior1 天前
Unity 7.0 Alpha 拆解:编辑器干掉 Mono 换 CoreCLR
c#·unity3d·游戏开发
淡海水1 天前
02-06-原理篇-增量式GC与并发GC
算法·unity·c#·并发·gc·增量
Vertira1 天前
C# 函数封装成 DLL,
开发语言·c#
浅尝辄止;1 天前
设计模式在HIS/LIS医疗系统中的完整实践指南(C#版)
开发语言·设计模式·c#
kimloner1 天前
开源一个 376KB 的 Windows 桌面小工具:便签 + 截图标注 + OCR + 待办提醒(C# / WinForms)
windows·开源·c#·ocr·winforms
longlongzihan1 天前
链表找环:Floyd 判圈算法(LeetCode 141 & 142 )
c++·算法·leetcode·链表