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
相关推荐
小肝一下10 分钟前
3. 单链表
c语言·数据结构·c++·算法·leetcode·链表·dijkstra
czhc114007566338 分钟前
722:零侵入;DBG;
c#
-银雾鸢尾-10 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-10 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
心平气和量大福大14 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
白露与泡影14 小时前
Arthas 实战指南:从方法耗时定位到 JVM 变量热修改
服务器·jvm·c#
EIP低代码平台19 小时前
EIP低代码平台系统-字典功能讲解
低代码·c#·工作流
吉普赛的歌20 小时前
YARP负载均衡配置了多个相同接口导致的报错
c#·yarp
张人玉21 小时前
C# WinForms——工厂管理系统(C# WinForms)
数据库·sqlite·c#·winform
夜莺悠吟1 天前
关于对 C# 中 ImplicitUsings,GlobalUsings 的讨论
c#·.net