NET深拷贝实现方法与详细步骤解析
在 .NET 中实现深拷贝(Deep Copy)有几种常用方法
咱们先明确一下概念:深拷贝要做的,可不是简单地复制一个引用指针。它意味着创建一个全新的对象,并且像“开枝散叶”一样,递归地复制原对象及其内部所有引用对象的值。这和浅拷贝只复制“表面”有着本质区别。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
1. 使用序列化/反序列化
这招算是“经典流派”了,通过把对象序列化成二进制流,再反序列化回来,自然就得到了一个全新的副本。但有个前提,你的相关类型都得是可序列化的。
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
public static class ObjectCopier
{
public static T DeepCopy(T obj)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", nameof(obj));
}
if (ReferenceEquals(obj, null))
{
return default;
}
IFormatter formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
2. 使用 JSON 序列化(Newtonsoft.Json 或 System.Text.Json)
随着JSON的普及,这方法现在用得越来越多了。它本质上是把对象“翻译”成JSON文本,然后再“翻译”回来,实现拷贝。两种主流库都可以用,选择哪个看你的项目环境。
// 使用 Newtonsoft.Json using Newtonsoft.Json; public static T DeepCopy(T obj) { var json = JsonConvert.SerializeObject(obj); return JsonConvert.DeserializeObject (json); } // 使用 System.Text.Json (推荐.NET Core 3.0+) using System.Text.Json; public static T DeepCopy (T obj) { var json = JsonSerializer.Serialize(obj); return JsonSerializer.Deserialize (json); }
3. 实现 ICloneable 接口(手动实现)
如果你需要更精细的控制,或者对象结构特殊,手动实现ICloneable接口是个可靠的选择。这种方式需要你亲自动手,为每个引用类型成员安排“克隆”工作,灵活性最高。
public class MyClass : ICloneable
{
public int Value { get; set; }
public MyOtherClass Other { get; set; }
public object Clone()
{
var copy = (MyClass)MemberwiseClone(); // 先来个浅拷贝
copy.Other = (MyOtherClass)Other.Clone(); // 再手动深拷贝引用成员
return copy;
}
}
public class MyOtherClass : ICloneable
{
public string Name { get; set; }
public object Clone()
{
return MemberwiseClone(); // 如果成员都是值类型,浅拷贝就够了
}
}
4. 使用 AutoMapper(适用于复杂对象)
当面对属性众多、层次复杂的对象图时,配置一次AutoMapper,之后就可以优雅地一键深拷贝了。它特别适合在项目已经引入该库,或者对象结构非常规整的场景。
using AutoMapper;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap();
cfg.CreateMap();
});
var mapper = config.CreateMapper();
var copy = mapper.Map(original);
5. 注意事项
方法虽多,但各有利弊,选择时别忘了下面这些潜在的“坑”:
- 可序列化是门槛:序列化方法要求所有相关类都得是可序列化的(要么标记
[Serializable]特性,要么能被JSON序列化器处理)。 - 小心循环引用:如果对象内部存在A引用B,B又引用A这样的情况,很容易导致堆栈溢出或者序列化直接报错。
- 性能有差异:对于大型、嵌套很深的对象图,序列化/反序列化的开销不容忽视,可能会成为性能瓶颈。
- 特殊类型需处理:像委托、事件、COM对象这些特殊成员,上述通用方法很可能无法正确拷贝,需要额外处理。
6. 推荐方法
说了这么多,到底该怎么选?这里有个简单的决策思路:
- 对于简单对象或临时拷贝:直接用JSON序列化(特别是
System.Text.Json,在.NET Core环境下性能表现更佳)。 - 对于结构清晰的复杂对象图:考虑配置
AutoMapper或者老老实实实现ICloneable接口,以获得更好的可控性。 - 对于性能极其敏感的场景:没有银弹,手动实现深拷贝逻辑通常是最终方案,虽然开发成本高,但性能最优。
总而言之,没有绝对最好的方法,只有最适合当前场景的选择。综合考量你的具体需求、对象结构的复杂程度以及对性能的要求,才能做出最合适的决定。
热门专题
热门推荐
安币合约交易中,开仓与平仓是核心操作。开仓需选择合约类型、方向,设置杠杆与价格,并管理风险。平仓则分为止盈止损、市价及手动平仓,关键在于执行计划。新手应理解保证金机制,从小额开始,避免情绪化交易,逐步积累经验。
《星际火狐》新作公布后角色新设计引发争议。原设计师今村孝矢表示未参与此次监修,并坦言偏爱电影版福克斯形象,但对新版明确的设计方向持开放态度。作为系列经典重制,新作回归令创作者欣慰,角色革新虽伴随争议,但有望如过往案例般逐渐被接纳。
《找个球》第18关考验玩家的观察力与细致程度。本关需要玩家在画面中找出所有不同之处,其中两位角色身上就隐藏着4处关键差异,而背景中的盆景造型、挂画内容、灯笼样式以及窗户细节等处也均有变化。想要快速通关,可以参考下方的详细答案图解进行逐一核对。 《找个球》全关卡图文通关攻略合集 《找个球》第18关通关
在《三国杀:武将觉醒》的众多限定招募武将中,无双品质的「貂蝉」以其独特的辅助机制与战场掌控力,成为许多玩家阵容构筑的核心选择。这位以曼妙舞姿影响战局的佳人,不仅能显著加速自身的行动频率,还能为队友提供强大的攻击力加成与护盾保护。其专属武器的效果,更让她在面对男性武将时占据优势。当星级提升后,她甚至能
《找个球》第17关的挑战正式开启。本关的找不同图片中,两位主要角色身上隐藏着六处关键差异,同时周围的荷花丛中也分布着多处不易察觉的细节。部分变化非常细微,需要玩家集中注意力,仔细对比观察。无需担心,下方提供的通关答案图将为您提供清晰的指引,对照查找即可顺利过关。 想要一次性获取所有关卡的通关秘籍?欢





