icloneable 不推荐使用,因 clone() 返回 object 易致类型转换错误,且不区分深浅拷贝;应改用 memberwiseclone() 封装浅拷贝、json 序列化实现深拷贝,或手动构造。

ICloneable 接口在现代 C# 中不推荐直接使用,它只声明一个返回 object 的 Clone() 方法,既不保证深拷贝也不约束语义,容易引发运行时类型转换错误和共享引用 bug。
为什么 ICloneable.Clone() 返回 object 是个坑
调用方必须手动强制转换,比如 (Person)person.Clone(),一旦实现类返回了错误类型(如 null、其他子类、或未处理异常),编译器完全无法捕获。.NET 5+ 的分析器已将其实现标记为“不建议使用”(CA2213 等规则)。更糟的是,很多老项目默认把它当浅拷贝用,但文档没写清,接手人一调 Clone() 就踩进引用共享的坑里。
- 返回
object→ 每次调用都得写冗余 cast,还可能抛InvalidCastException - 接口不区分深/浅 → 同一个接口名,在不同类里行为可能完全不同
- 值类型不该实现它 → 值类型赋值本身就是深拷贝,实现
ICloneable反而误导使用者
MemberwiseClone() 是浅拷贝的事实标准,但只能在类内部调用
MemberwiseClone() 是 Object 类的 protected 方法,它不做任何构造函数调用,只按字段逐个复制:值类型复制值,引用类型复制地址。这是最轻量、最可控的浅拷贝方式,但你不能在类外部直接调它。
- 必须封装在
public方法里,例如public Person ShallowCopy() => (Person)this.MemberwiseClone(); - 数组字段调
Array.Clone()仍是浅的 —— 如果数组元素是引用类型,新旧数组仍指向同一组对象 -
string和DateTime等不可变引用/值类型,直接复制安全,不用额外处理
真要深拷贝,别硬刚 ICloneable,改用序列化或手动构造
靠 ICloneable 实现可靠深拷贝,等于自己重造轮子还漏气。现代项目优先选 System.Text.Json 序列化,或对关键字段手动 new + 复制。
- JSON 深拷贝示例:
JsonSerializer.Deserialize<person>(JsonSerializer.Serialize(person))</person>—— 要求类型可序列化,自动跳过[JsonIgnore]字段,不支持event或delegate - 二进制序列化(
BinaryFormatter)已废弃,.NET Core 3.0+ 默认禁用,别碰 - 手动深拷贝适用场景:对象结构固定、含不可序列化资源(如文件句柄)、或性能敏感 → 先
MemberwiseClone(),再对每个需隔离的引用字段(如List<t></t>)调new List<t>(originalList)</t>或遍历AddRange
如果必须保留 ICloneable 兼容性,至少明确命名和注释
遗留系统升级时,有时无法立刻移除 ICloneable。这时不要让它继续叫 Clone(),而应显式暴露意图。
- 实现方法命名为
ShallowClone()或DeepClone(),并在 XML doc 注明行为和限制 - 避免在接口层暴露
ICloneable,改为提供具体类型方法,如public Person CloneAsNewInstance() - 若类含循环引用或非序列化字段,JSON 深拷贝会失败,此时必须走手动路径 —— 这一点常被忽略,直到上线后数据错乱才暴露











