C#怎么实现深拷贝和浅拷贝 C# ICloneable接口使用方法

来源:这里教程网 时间:2026-02-21 17:37:57 作者:

在 C# 中,浅拷贝(Shallow Copy)只复制对象的值类型字段和引用类型的地址(即新旧对象共享同一引用对象),而深拷贝(Deep Copy)会递归复制所有层级的对象,确保新对象与原对象完全独立。实现方式有多种,

ICloneable
接口是传统方法之一,但需注意它本身不区分深浅,具体行为由你实现决定。

浅拷贝:MemberwiseClone 是最直接的方式

Object.MemberwiseClone()
是 .NET 提供的内置浅拷贝方法,它创建一个新对象,并将当前对象的字段值逐个复制过去。值类型被复制值,引用类型被复制引用(地址)。

只能在类内部调用(因为是
protected
方法)
无需实现接口,开销小,适合简单结构 若类中包含数组、集合或自定义引用类型,它们不会被重新创建,新旧对象仍指向同一实例

示例:

class Person { public string Name; public Address Addr; }
class Address { public string City; }
var p1 = new Person { Name = "Alice", Addr = new Address { City = "Beijing" } };
var p2 = (Person)p1.MemberwiseClone(); // 浅拷贝
p2.Addr.City = "Shanghai"; // p1.Addr.City 也会变成 "Shanghai"

深拷贝:推荐使用序列化或手动克隆

没有通用的“一键深拷贝”机制,常见可靠方式有:

JSON 序列化(推荐用于简单 POCO 类):用
System.Text.Json
Newtonsoft.Json
序列化再反序列化,天然实现深拷贝(前提是类型可序列化且无循环引用)
二进制序列化(已过时,不建议新项目使用):依赖
[Serializable]
,且类型必须标记为可序列化,.NET Core/.NET 5+ 中默认禁用
手动实现 Clone 方法:对每个引用字段显式 new 并复制,控制力最强,适合复杂逻辑或性能敏感场景

JSON 示例(.NET Core 3.0+):

var json = JsonSerializer.Serialize(p1);
var p2 = JsonSerializer.Deserialize(json); // 完全独立的新对象

ICloneable 接口:语义约定,不是语法保障

ICloneable
只定义了一个
Clone()
方法,它不指定是深还是浅——这是开发者责任。很多老代码或文档里把它等同于“浅拷贝”,但实际应以文档或实现为准。

实现时需明确注释说明是深还是浅,否则极易引发 bug 返回类型是
object
,调用方需强制转换,不够类型安全
.NET 团队已将其标记为“不推荐使用”(obsoleted in .NET 5+ 的某些分析规则中),现代代码更倾向用专用方法如
CloneDeep()
或构造函数传参

示例(显式声明为深拷贝):

class Person : ICloneable {
  public string Name; public Address Addr;
  public object Clone() => new Person {
    Name = this.Name,
    Addr = this.Addr == null ? null : new Address { City = this.Addr.City }
  };
}

实用建议:按场景选方案

只要复制一层字段,且不含复杂引用 → 用
MemberwiseClone
数据简单、可序列化、不追求极致性能 → 用
JsonSerializer
深拷贝
需要精确控制每一步(比如跳过某些字段、处理循环引用、调用自定义初始化)→ 手写克隆逻辑 团队协作或公共库中 → 避免仅靠
ICloneable
,改用命名清晰的方法如
With(...)
DeepCopy()
或记录类型(record)的
with
表达式

基本上就这些。深浅拷贝本质是对象图遍历策略的选择,关键是理解你的数据结构和共享意图,而不是迷信某个接口或方法名。

相关推荐