MemberwiseClone仅浅拷贝字段引用,非深拷贝;仅当对象全为值类型或不可变引用类型(如string)时安全;ICloneable不保证深拷贝,.NET已标记过时;深拷贝需序列化、手动克隆或第三方库,各有利弊。

MemberwiseClone 只做浅拷贝,不是“复制对象”而是“复制字段引用”,想真正隔离修改影响,必须用深拷贝——但 C# 没有开箱即用的通用深拷贝机制,得自己选方案、踩坑、权衡。
什么时候 MemberwiseClone 就够用了
当你确认对象里全是值类型(int、DateTime、struct),或者引用类型字段本身是不可变的(比如 string、ImmutableArray<t></t>),那 MemberwiseClone 就是安全且高效的。
-
MemberwiseClone是protected方法,必须在类内部调用,不能直接对任意实例用 - 它不调用任何构造函数,也不触发属性 setter,纯字段级复制
- 如果类里有
IDisposable字段,浅拷贝后两个对象会共用同一资源,可能引发ObjectDisposedException
为什么 ICloneable.Clone 不能直接当深拷贝用
接口本身不规定语义,ICloneable 的 Clone 方法返回 object,实现者可以返回浅拷贝、深拷贝,甚至返回 this。.NET 官方文档明确说它“已过时”,不推荐新代码使用。
- 你看到别人写了
public object Clone() => this.MemberwiseClone();,这仍是浅拷贝 - 若真要深拷贝,得在
Clone方法里手动 new 引用类型字段,或递归调用其Clone - 没有编译器或运行时检查,调用方根本不知道这个
Clone是深是浅
深拷贝的三种实操路径和取舍
没有银弹,只有场景适配:
-
序列化反序列化:最简单粗暴,要求所有类型标记
[Serializable]或实现ISerializable;用JsonSerializer.Serialize+Deserialize更现代,但会丢失私有字段、事件、readonly修饰符,且性能差 - 手动克隆:在每个需要深拷贝的类中写构造函数或工厂方法,显式 new 所有引用字段;可控、高效、可调试,但维护成本高,容易漏字段
-
第三方库(如
DeepCloner或FastDeepCloner):基于表达式树或 IL 生成,支持泛型、循环引用检测;但引入依赖、反射开销仍存在,某些场景(如含指针、unsafe代码)不支持
最容易被忽略的细节:string 和集合类型
string 在浅拷贝中表现像值类型,是因为它是不可变引用类型——复制引用没问题,改内容会新建实例。但集合不是:
-
List<t></t>、Dictionary<k></k>浅拷贝后,新旧对象共享同一个内部数组,Add、Clear都会影响对方 - 哪怕你深拷贝了集合对象本身,如果
T是引用类型,里面元素还是原引用;要真正隔离,得递归深拷贝元素(除非T是值类型或不可变类型) - 自定义集合类如果缓存了计算结果(比如
Count属性背后有 lazy 字段),浅拷贝会把缓存状态也“共享”过去


















