memberwiseclone()仅支持浅拷贝,对引用类型只复制地址;深拷贝应优先用system.text.json序列化反序列化,或手动实现icloneable逐层克隆,避免引用共享问题。

用 MemberwiseClone() 只能浅拷贝,别踩这个坑
很多人一上来就试 MemberwiseClone(),发现引用类型字段还是共用同一块内存——改副本的 List<string></string>,原对象也跟着变。这是因为 MemberwiseClone() 本质是位拷贝,对引用字段只复制地址,不递归克隆内容。
它只适合纯值类型、且不含任何引用成员的简单结构体;一旦类里有 string(虽不可变但仍是引用)、Dictionary<int object></int>、自定义类字段等,立刻失效。
- 不要给含集合、嵌套对象的类加
ICloneable并只实现MemberwiseClone() - 测试时务必修改副本中的引用字段内容,再检查原对象是否变化
-
struct默认按值传递,多数场景下不需要深拷贝,别无脑套用
序列化反序列化是最稳的通用方案
把对象转成 JSON 或二进制流再读回来,天然绕过引用共享问题。推荐优先用 System.Text.Json(.NET Core 3.0+)或 Newtonsoft.Json,比 BinaryFormatter 安全、跨平台、无 [Serializable] 强制要求。
示例(System.Text.Json):
var options = new JsonSerializerOptions { WriteIndented = true };
var json = JsonSerializer.Serialize(original, options);
var clone = JsonSerializer.Deserialize<myclass>(json, options);</myclass>
- 必须确保所有层级的类都可被序列化(无循环引用、无
IntPtr、无不可序列化字段如event) - 若字段含
DateTimeOffset、TimeSpan等,注意JsonSerializerOptions的默认行为(比如时区处理) - 性能敏感场景慎用:JSON 解析有开销,大对象反复深拷贝会明显拖慢
手动实现 ICloneable 要逐层 new,不能偷懒
当对象结构固定、性能关键、且需完全控制拷贝逻辑时,手动写 Clone() 最直接。核心原则:每个引用类型字段都要显式调用其构造函数或 Clone() 方法,不能直接赋值。
例如:
public class Person : ICloneable
{
public string Name { get; set; }
public List<address> Addresses { get; set; }
public object Clone()
{
var clone = (Person)MemberwiseClone();
clone.Addresses = Addresses?.Select(a => (Address)a.Clone()).ToList(); // 关键:递归克隆
return clone;
}
}</address>
- 子类若重写了
Clone(),父类实现必须调用base.Clone()并转型,否则丢失基类字段 - 集合类别直接
new List<t>(originalList)</t>——这只是浅拷贝,元素仍是原引用 - 字段为
readonly时,无法在Clone()中赋值,得用反射或构造函数绕过(不推荐)
第三方库如 DeepCloner 省事但要注意兼容性
DeepCloner(NuGet 包)用 IL Emit 动态生成拷贝代码,速度接近手写,又不用改业务类。但它依赖运行时生成代码,在 AOT 编译(如 .NET 8+ NativeAOT)或某些沙箱环境(如 Azure Functions 部分配置)下会失败。
基本用法:
var clone = DeepCloner.DeepClone(original);
- 支持泛型、继承、循环引用,默认跳过
static和const字段 - 若类含
IntPtr、SafeHandle或需要自定义拷贝逻辑,得配合DeepClonerSettings注册转换器 - 升级 .NET 版本后务必回归测试,IL 生成逻辑可能因 JIT 变更而异常











