c# 如何深拷贝和浅拷贝


浅拷贝用MemberwiseClone()仅复制第一层引用,新旧对象共享引用类型子对象;深拷贝推荐System.Text.Json序列化反序列化,安全高效;Newtonsoft.Json更灵活但需引入第三方包;禁用BinaryFormatter。

浅拷贝用 MemberwiseClone(),但只复制第一层引用

在 C# 中,MemberwiseClone() 是最直接的浅拷贝方式,它会创建新对象,并把原对象所有字段值(包括引用)逐字节复制过去。对值类型字段是真正复制,对引用类型字段只是复制“引用地址”,所以新旧对象仍共享同一堆内存中的子对象。

常见错误现象:修改拷贝后对象里的 List 或自定义类实例,原对象也跟着变——这就是浅拷贝的典型副作用。

使用场景有限:仅适用于字段全是值类型、或你明确知道引用字段不需要独立副本的情况(比如只读缓存对象)。

  • 必须是 class,且不能是 sealed 以外的限制(但 MemberwiseClone() 本身是 protected,需在类内部调用)
  • 不支持跨程序集深拷贝,也不处理循环引用
  • 性能高,但语义风险大,生产环境慎用

深拷贝推荐用 System.Text.Json 序列化反序列化

对大多数 POCO 类型,用 System.Text.Json 是目前最轻量、安全、无需额外依赖的深拷贝方案。它把对象转成 JSON 字符串再解析回来,天然切断所有引用关系。

示例:

var original = new Person { Name = "Alice", Address = new Address { City = "Beijing" } };
var clone = JsonSerializer.Deserialize(
    JsonSerializer.Serialize(original));

注意点:

  • 目标类型必须有无参构造函数(System.Text.Json 默认需要)
  • 不支持 DateTimeOffset 等部分类型默认序列化(需配置 JsonSerializerOptions
  • 忽略 [JsonIgnore][XmlIgnore] 属性,但不会跳过 private 字段(默认行为)
  • 性能比 BinaryFormatter 好,且无反序列化远程代码执行风险

需要保留类型/字段访问控制时用 Newtonsoft.Json

当你的类有 private setreadonly 字段,或继承结构复杂(如抽象基类 + 多个派生类),System.Text.Json 可能无法还原原始字段状态,这时 Newtonsoft.Json 更灵活。

它支持 JsonPropertyAttribute 控制序列化粒度,也能通过 PreserveReferencesHandling.Objects 处理循环引用(虽然深拷贝一般不希望保留引用)。

关键配置示例:

var settings = new JsonSerializerSettings
{
    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var clone = JsonConvert.DeserializeObject(
    JsonConvert.SerializeObject(original, settings), settings);

缺点也很明显:

  • 引入第三方 NuGet 包(Newtonsoft.Json
  • 序列化性能略低于 System.Text.Json
  • 若未设 ReferenceLoopHandling,遇到循环引用直接抛 JsonSerializationException

避免踩坑:别用 BinaryFormatter 做深拷贝

BinaryFormatter 曾是 .NET Framework 时代常用的深拷贝手段,但它在 .NET 5+ 已被标记为 不安全且废弃,官方明确不建议用于任何新代码。

原因很实在:

  • 反序列化过程可能执行任意代码(CVE-2017-0199 类风险)
  • 不支持跨版本兼容(.NET Core 和 .NET Framework 的二进制格式不一致)
  • 要求所有类型都标注 [Serializable],且字段不能含不可序列化的资源(如文件句柄、数据库连接)

如果你在老项目里看到 BinaryFormatter.Deserialize() 做拷贝,优先替换为 System.Text.Json 方案,哪怕要补几个 [JsonInclude] 或调整构造函数。

真正难的不是选哪种方式,而是判断“这个对象到底需不需要深拷贝”——比如一个只读的 DTO 传参,根本不需要拷贝;而一个正在被多线程修改的配置对象,浅拷贝可能引发竞态。动手前先想清楚数据生命周期和所有权。


# js  # json  # 字节  # c#  # .net  # String  # 构造函数  # 字符串  # 循环  # 继承  #   # class  # 值类型  # 引用类型  # private  # protected  # 线程  # 多线程  # 对象  # 数据库  # 序列化  # 不需要  # 不支持  # 第三方  # 第一层  # 更灵活  # 几个  # 也不  # 多个  # 句柄 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: Windows10系统服务优化指南_Win10禁用不必要服务提升性能  Python代码测试策略_质量保障解析【教程】  PythonPandas数据分析教程_数据清洗与处理技巧  VSC怎样在VSC中调试PHPAPI_接口调试技巧【详解】  如何使用Golang实现路由分组管理_Golang路由分组与权限控制方法  如何用正则与预处理结合精准拦截拼接式垃圾域名  海外搜索引擎推广效果怎么样,怎么分析效果!  c# 在高并发下使用反射发射(Reflection.Emit)的性能  Win11怎么设置默认终端应用_Windows11开发者选项终端  c++怎么编写动态链接库dll_c++ __declspec(dllexport)导出与调用【方法】  Win11怎样安装微信开发者工具_Win11安装开发者工具教程【步骤】  如何在Golang中写入JSON文件_保存结构体数据到文件  如何在Golang中使用time处理时间_Golang time时间解析与格式化方法  如何用::实现单例模式_php静态方法与作用域操作符应用【技巧】  英国搜索:多数英国人认为语言搜索是未来搜索  Win11怎样彻底卸载自带应用_Win11彻底卸载自带应用方法【步骤】  Win11如何开启系统更新 Win11开启系统更新方法【步骤】  如何在Golang中指定模块版本_使用go.mod控制版本号  ACF 教程:正确更新嵌套在多层 Group 字段内的子字段  如何使用Golang构建基础消息队列模拟_Golang消息发送与消费实现方法  Win11怎么设置屏保_Windows 11屏幕保护程序开启与设置【详解】  如何使用正则表达式批量替换重复的星号-短横模式为固定字符串  MAC怎么用连续互通相机里的“桌上视角”_MAC在视频通话中同时展示人脸和桌面  Python函数缓存机制_lru_cache解析【指导】  php文件怎么变mp4保存_php输出视频流保存为mp4操作【操作】  Mac如何彻底清理浏览器缓存?(Safari与Chrome)  用lighttpd能运行php吗_lighttpd配置php步骤【教程】  Win10系统字体模糊怎么办_Windows10高级缩放设置修复  Win11如何暂停系统更新 Win11暂停更新最长时限设置【步骤】  如何理解Go指针和内存分配关系_Go Pointer内存Model解析  Python面向对象实战讲解_类与设计模式深入理解  PythonPandas数据分析项目教程_时间序列透视表应用  如何在 PHP 中按相同键合并两个关联数组为二维数组  C++如何解析JSON数据?(nlohmann/json库示例)  php下载安装后memory_limit怎么设置_内存限制调整【技巧】  php485在macos下怎么配置_php485 macOS系统配置指南【解答】  Windows11怎么自定义任务栏_Windows11任务栏自定义教程【步骤】  MAC的“接续互通”功能无法使用怎么办_MAC检查蓝牙、Wi-Fi和相同Apple ID登录  Win10如何更改网络连接_Windows10以太网属性IP配置  如何在Golang中实现邮件发送功能_Golang SMTP发送与错误处理示例  网站体验不好=浪费钱:如何提升-用户体验效果差  Python变量绑定机制_引用模型解析【教程】  Win11相机打不开提示错误怎么修_相机权限开启与驱动修复【影像修复】  PHP的FastAdmin架构适合二次开发吗_特点分析【介绍】  mac怎么查看wifi密码_MAC查看已连接WiFi密码方法【技巧】  php会话怎么开启_session_start函数的作用与使用时机【方法】  Windows10如何更改任务栏高度_Win10解除锁定调整大小  Win11怎么连接投影仪_Win11多显示器投屏设置指南【步骤】  Windows如何设置登录时的欢迎屏幕背景?(锁屏界面)  C++ STL算法库怎么用?C++常用算法函数(sort, find)教程【效率提升】 

 2026-01-02

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.