You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中Object.MemberwiseClone下string为何表现出值类型特性?

问题原因解答

核心差异来自两个点:string的不可变特性,以及你对两个引用类型的修改操作本质完全不同。

首先明确浅拷贝的统一规则

MemberwiseClone实现的浅拷贝逻辑对所有引用类型都一致:

  • 对值类型字段,拷贝字段本身的值
  • 对引用类型字段,仅拷贝字段存储的堆对象引用地址,原对象和拷贝对象的同名字段会指向堆上的同一个对象
    该规则对string和自定义的IdInfo类型完全适用,没有例外。

两种修改操作的本质差异

1. IdInfo的修改操作

你执行的代码是p1.IdInfo.IdNumber = 7878:
这个操作的本质是修改p1和p2共同指向的同一个IdInfo堆对象的内部属性,并没有改变p1.IdInfo字段本身存储的引用地址。因为两个对象的IdInfo字段始终指向同一个堆实例,所以修改内部属性后,p2访问时自然会同步看到变更。

2. string类型Name的修改操作

你执行的代码是p1.Name = "Frank":
C#中string是不可变类型,一旦创建字符串实例,就无法修改实例本身的内容。所以这个赋值操作的本质不是修改原来的"Sam"字符串对象的内容,而是创建了一个新的"Frank"字符串实例,让p1的Name字段指向这个新的实例。
此时p2的Name字段仍然指向原来的"Sam"字符串实例,两个对象的Name字段已经指向不同的堆对象,自然不会同步变更。

补充说明

如果用非常规手段(比如unsafe语法直接修改字符串实例的内存内容)修改原"Sam"字符串的内容,你会发现p2的Name也会同步变化,这也验证了浅拷贝对string的处理逻辑和其他引用类型完全一致,只是日常开发中不会出现修改字符串实例内容的操作,都是直接重新赋值,所以不会出现同步变更的现象。
另外你代码深拷贝逻辑中的String.Copy(Name)实际上没有必要,因为string不可变的特性,即使两个对象的Name字段指向同一个字符串实例,也不会出现互相修改的问题,这段处理更多是兼容极端场景的冗余写法。

内容的提问来源于stack exchange,提问作者rustyBucketBay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 13:45:02