dotnet 值拷贝、浅拷贝、深拷贝详解
zhezhongyun 2025-05-14 18:26 1 浏览
简介
在 .NET 中,值拷贝(Value Copy)主要指的是将一个 值类型 的实例或对象的值复制到另一个变量中,使两个变量之间互不影响。我们可以从几个维度来详细理解:
值拷贝的本质
.NET 中的类型分为:
- 值类型(Value Type):例如 int、float、bool、DateTime、struct 自定义结构体
- 引用类型(Reference Type):例如 string(特殊值行为)、class、object、array、List<T> 等
值类型在赋值时是拷贝值本身,引用类型则是拷贝引用(地址)。
值类型是值拷贝
int a = 10;
int b = a; // 值拷贝
b = 20;
Console.WriteLine(a); // 输出 10,不受 b 更改影响
引用类型是引用拷贝
class Person
{
public string Name;
}
Person p1 = new Person { Name = "Alice" };
Person p2 = p1; // 引用拷贝,指向同一对象
p2.Name = "Bob";
Console.WriteLine(p1.Name); // 输出 Bob,p1 也被修改了
自定义结构体也是值类型(值拷贝)
struct Point
{
public int X;
public int Y;
}
Point p1 = new Point { X = 1, Y = 2 };
Point p2 = p1; // 值拷贝
p2.X = 100;
Console.WriteLine(p1.X); // 1
Console.WriteLine(p2.X); // 100
结构体之间的赋值是完全拷贝一份内存,不影响原来的结构体变量。
浅拷贝 vs 深拷贝(类场景)
如果需要让 引用类型 的对象像 值类型 一样“复制”,就要实现:
- 浅拷贝(Shallow Copy):复制对象的字段引用
- 深拷贝(Deep Copy):复制整个对象图结构
使用 MemberwiseClone() 实现浅拷贝(只能在类内部使用)
public class Person
{
public string Name;
public Address Address;
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
}
public class Address
{
public string City;
}
// 使用
var original = new Person { Name = "Alice", Address = new Address { City = "New York" } };
var copy = original.ShallowCopy();
copy.Name = "Bob";
copy.Address.City = "London";
Console.WriteLine(original.Name); // 输出: Alice
Console.WriteLine(original.Address.City); // 输出: London(共享引用)
实现深拷贝的常用方式
- 自己 new 一个新对象,手动复制字段
public class Person
{
public string Name;
public Address Address;
public Person DeepCopy()
{
return new Person
{
Name = this.Name,
Address = new Address { City = this.Address.City }
};
}
}
// 使用
var original = new Person { Name = "Alice", Address = new Address { City = "New York" } };
var copy = original.DeepCopy();
copy.Name = "Bob";
copy.Address.City = "London";
Console.WriteLine(original.Name); // 输出: Alice
Console.WriteLine(original.Address.City); // 输出: New York(独立)
- 使用序列化反序列化(如 Newtonsoft.Json 或 System.Text.Json)
public static T DeepCopy<T>(T obj)
{
string json = JsonSerializer.Serialize(obj);
return JsonSerializer.Deserialize<T>(json);
}
// 使用
var original = new Person { Name = "Alice", Address = new Address { City = "New York" } };
var copy = DeepCopy(original);
copy.Address.City = "London";
Console.WriteLine(original.Address.City); // 输出: New York
- 反射或表达式树:动态生成深拷贝逻辑。
public static object DeepCopyReflection(object original) {
if (original == null) return null;
Type type = original.GetType();
object copy = Activator.CreateInstance(type);
foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
object value = field.GetValue(original);
if (value is ICloneable cloneable)
field.SetValue(copy, cloneable.Clone());
else
field.SetValue(copy, DeepCopyReflection(value));
}
return copy;
}
- 使用第三方库:DeepCloner 实现深拷贝
using System;
using Force.DeepCloner;
public class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
}
class Program
{
static void Main()
{
var original = new Person
{
Name = "Alice",
Address = new Address { City = "New York" }
};
// 深拷贝对象
var copy = original.DeepClone();
copy.Name = "Bob";
copy.Address.City = "London";
Console.WriteLine(original.Name); // 输出: Alice
Console.WriteLine(original.Address.City); // 输出: New York(独立)
}
}
- 使用第三方库:DeepCloner 处理复杂对象图
DeepCloner 支持嵌套对象、集合和循环引用的深拷贝。
public class Company
{
public List<Employee> Employees { get; set; }
}
public class Employee
{
public string Name { get; set; }
public Company Company { get; set; }
}
class Program
{
static void Main()
{
var company = new Company();
var employee = new Employee { Name = "Alice", Company = company };
company.Employees = new List<Employee> { employee };
// 深拷贝(处理循环引用)
var companyCopy = company.DeepClone();
companyCopy.Employees[0].Name = "Bob";
Console.WriteLine(company.Employees[0].Name); // 输出: Alice(独立)
}
}
性能优化
DeepCloner 通过缓存和 IL 代码生成实现高性能深拷贝,适合高频调用场景。
基准对比
方法 | 耗时(1000次深拷贝) | 内存占用 |
DeepCloner | ~10 ms | 低 |
Json序列化 | ~200 ms | 高 |
手动深拷贝 | ~5 ms(简单对象) | 低 |
- 使用 AutoMapper 进行深度拷贝
using AutoMapper;
using System;
// 定义源对象类
public class Source
{
public int Id { get; set; }
public string Name { get; set; }
}
// 定义目标对象类
public class Destination
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main()
{
// 配置映射
var config = new MapperConfiguration(cfg => cfg.CreateMap<Source, Destination>());
var mapper = config.CreateMapper();
// 创建源对象
var source = new Source { Id = 1, Name = "Example" };
// 进行映射(拷贝)
var destination = mapper.Map<Destination>(source);
Console.WriteLine(#34;Id: {destination.Id}, Name: {destination.Name}");
}
}
- 使用 ExpressMapper 进行深度拷贝
ExpressMapper 是一个高性能的对象映射库,它利用表达式树来生成映射代码,从而实现快速的对象映射和拷贝。它支持复杂的映射规则和自定义转换,并且具有良好的性能表现。
using ExpressMapper;
using System;
// 定义源对象类
public class SourceClass
{
public int Value { get; set; }
}
// 定义目标对象类
public class DestinationClass
{
public int Value { get; set; }
}
class Program
{
static void Main()
{
// 配置映射
Mapper.Register<SourceClass, DestinationClass>();
// 创建源对象
var source = new SourceClass { Value = 10 };
// 进行映射(拷贝)
var destination = Mapper.Map<SourceClass, DestinationClass>(source);
Console.WriteLine(#34;Value: {destination.Value}");
}
}
- 上一篇:41 基于Sentinel的限流
- 下一篇:如何用控制台打印日历?
相关推荐
- Axure教程
-
来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。前几天看到有人介绍了axure8的图片放大原型设计步骤(http://www.woshipm.com/rp/24687...
- 保姆级教程:手把手教你用 Readdy.ai 轻松产品设计与前端开发
-
本文将为你介绍一款强大的AI工具——Readdy.ai,它不仅能自动生成精美的UI设计稿,还能直接生成可用的前端代码,极大地提升了开发效率。前几天雷神为大家介绍了一款AI设计工具莫高设计,但是...
- 前端学习保姆级教程,轻松入门 Web 开发
-
在当今数字化时代,我们每天浏览的网页、使用的各类应用,其美观的界面、流畅的交互体验背后,都离不开前端开发技术的支撑。前端开发,简单来说,就是负责将网站或应用的界面呈现给用户,它直接影响着用户对产品的第...
- 分享几个css实用技巧
-
本篇将介绍几个css小技巧,目录如下:自定义引用标签的符号重置所有标签样式禁止文本选择制作小三角形自定义<q>引用标签的符号默认q标签引用符号是浏览器根据不同语言环境自动设置的,当然我们也...
- 五步做一个高保真可交互原型-Principle教程
-
这篇教程要介绍的案例是:App界面上调整时间的可交互原型。我们先看一下效果:这个案例用的是Principle这款软件做的。Principle近段时间非常流行的一款做原型的软件。很多公司也用Princi...
- asp网站源码安装教程
-
asp网站源码安装指南1、打开控制面板并单击2、点选管理工具选项3、请单击打开Internet信息服务(IIS)管理器应用查看4、点击开始按钮5、请将项目文件移动到C:inetpubwwwr...
- web前端HTML教程——开发环境搭建下载和安装编辑器
-
html开发环境搭建有一个好的编辑器我们可以方便地的开发项目,编写代码,配置和管理我们的项目。所以我们开始编写html代码之前需要搭建开发环境。基于html项目的开发和代码编写现在网上有很多编辑器,也...
- 如何用控制台打印日历?
-
朋友们大家好,今天我给大家带来一个控制台小程序——打印当月的日历,效果如下图:笔者运行这个程序的时候是2022年7月30日,所以在日期的30后面加了一个*符号。这个程序很简单,但有些知识点我也会为大家...
- dotnet 值拷贝、浅拷贝、深拷贝详解
-
简介在.NET中,值拷贝(ValueCopy)主要指的是将一个值类型的实例或对象的值复制到另一个变量中,使两个变量之间互不影响。我们可以从几个维度来详细理解:值拷贝的本质.NET中的类型分...
- 41 基于Sentinel的限流
-
Sentinel支持对SpringCloudGateway、Zuul等主流的APIGateway进行限流。从1.6.0版本开始,Sentinel提供了SpringCloud...
- Java反射机制:神秘之门的钥匙
-
Java反射机制:神秘之门的钥匙什么是Java反射?当你第一次听说Java反射的时候,你可能会感到困惑。简单来说,Java反射就是让你在程序运行时动态地操作类和对象的能力。这就像一把钥匙,能够打开Ja...
- Java反射机制:魔法般的代码操控
-
Java反射机制:魔法般的代码操控在这个充满无限可能的编程世界里,Java反射机制就像一位神秘的魔法师,它允许程序在运行时检查类、方法、字段等信息,甚至还能动态调用这些成员。这种能力让Java开发者能...
- 自己动手从0开始实现一个分布式 RPC 框架
-
前言为什么要自己写一个RPC框架,我觉得从个人成长上说,如果一个程序员能清楚的了解RPC框架所具备的要素,掌握RPC框架中涉及的服务注册发现、负载均衡、序列化协议、RPC通信协议、Socket通信、异...
- C# 实战指南:使用 iText7 高效处理 PDF 文件
-
1.引言在现代开发中,处理PDF文件是一个常见的需求,例如生成报告、填充表单、设置权限或签名等。iText7是一个功能强大的PDF操作库,支持多种PDF操作,包括表单填充、加密、数字签...
- 手写代码生成工具实现类似Mybatis-Plus的效果-----02
-
#全新智己L6全国试驾开启#packagecom.alatus.builder;importcom.alatus.Entity.FieldInfo;importcom.alatus.Ent...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- HTML 参考手册 (28)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML常用标签 (29)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)