memberwiseclone()仅支持浅拷贝,对引用类型只复制地址;深拷贝推荐system.text.json序列化反序列化,安全高效,适用于大多数poco类。

别用 MemberwiseClone() 做深拷贝——它只复制引用地址,改副本的 List<string></string>,原对象立刻同步变。真要深拷贝,得看对象结构、性能要求和运行环境,没有“一招鲜”。
System.Text.Json.Serialize/Deserialize 是最稳的通用方案
适用于 .NET Core 3.0+ 或 .NET 5+ 项目,无需标记 [Serializable],不依赖 BinaryFormatter(已废弃且不安全),天然规避引用共享。
- 必须确保所有嵌套类型可序列化:不能含
IntPtr、event字段、未公开 setter 的只读集合等 - 循环引用会直接抛
InvalidOperationException: Circular reference detected,得提前用ReferenceHandler.Preserve处理(但会引入$id/$ref,语义变复杂) -
DateTimeOffset、TimeSpan默认按 ISO 8601 序列化,时区信息保留;若需 UTC 统一格式,设JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull并配合Converters - 示例:
var options = new JsonSerializerOptions { WriteIndented = true };
var json = JsonSerializer.Serialize(original, options);
var clone = JsonSerializer.Deserialize<myclass>(json, options);</myclass>
手动实现 ICloneable 时,每个引用字段都得 new 或 Clone()
适合结构固定、性能敏感、或需控制字段级行为(比如跳过日志缓存、重置 ID)的场景。偷懒写 new MyClass { Prop = this.Prop } 就等于没做深拷贝。
- 值类型字段可直接赋值;
string虽是引用类型但不可变,通常可直接赋值(除非你明确要隔离 intern 池行为) -
List<t></t>、Dictionary<k></k>等集合必须逐项调用new List<t>(sourceList)</t>或sourceList.Select(x => x.Clone()).ToList() - 嵌套自定义类字段不能写
Nested = this.Nested,必须显式调用其Clone()方法或构造函数:Nested = this.Nested?.Clone() ?? null - 别忘了处理
null:字段为null时直接赋null,否则?.Clone()会崩
BinaryFormatter 已废弃,仅限遗留 .NET Framework 项目且无法升级时临时用
它要求所有类型打 [Serializable],反序列化时可能执行任意代码(RCE 风险),.NET Core/.NET 5+ 默认禁用,强开需配置 AppContext.SetSwitch("Switch.System.Runtime.Serialization.EnableUnsafeBinaryFormatterDeserialization", true) —— 这不是建议,是警告。
- 遇到
SerializationException: Type 'xxx' in Assembly 'xxx' is not marked as serializable,不是加个特性就能解决,第三方库类往往根本不可序列化 - 含
ThreadStatic、NonSerialized字段时行为难预测,调试成本高 - 跨平台(如 Linux/macOS)下部分类型序列化结果不一致,别指望它稳定
反射克隆性能比 JSON 好,但容易漏字段或崩在 private set
用 GetFields(BindingFlags.NonPublic | BindingFlags.Instance) + 递归 DeepCopyByReflect() 可绕过序列化限制,但实际落地很脆。
- 只读属性(
get有、set无)拿不到字段,PropertyInfo.SetValue()会抛异常 - 自动属性背后字段名是编译器生成的(如
<name>k__BackingField</name>),不同编译器版本可能不同,靠名字匹配不可靠 - 静态字段、常量、
const、readonly字段会被复制,但多数场景不该拷贝它们 - 性能虽比 JSON 快约 5 倍,但首次调用反射有 JIT 开销,小对象反复拷贝反而不如 JSON 稳定
真正麻烦的从来不是“怎么写”,而是“哪些字段不该深拷贝”——比如数据库连接、事件委托、缓存句柄。深拷贝前先画清楚对象图,标出哪些引用必须隔离、哪些可以共享,比选哪种技术重要得多。










