0

0

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

幻夢星雲

幻夢星雲

发布时间:2026-01-13 12:15:25

|

420人浏览过

|

来源于php中文网

原创

浅拷贝仅复制值类型字段和引用类型地址,深拷贝递归复制所有层级;MemberwiseClone是内置浅拷贝方法,JSON序列化是推荐的深拷贝方式,ICloneable接口不区分深浅且已不推荐使用。

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

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

JSON 示例(.NET Core 3.0+):

绘蛙-多图成片
绘蛙-多图成片

绘蛙新推出的AI图生视频工具

下载
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 表达式

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

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

411

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

532

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

309

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

231

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

435

2024.03.01

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

533

2023.12.01

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

1

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.2万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号