C# 浅拷贝和深拷贝
本文主要通过事例分析引用类型的浅拷贝和深拷贝之间的区别,
还是从代码开始吧:
一、浅拷贝:
声明一个将要被克隆的类 clsShallow 和它将要包含的引用类型成员clsRefSalary类,clsShallow包含 CompanyName(静态字符串)、Age(值类型)、EmployeeName(字符串)、EmpSalary(引用类型)四个成员。
public class clsShallow { public static string CompanyName = "My Company"; public int Age; public string EmployeeName; public clsRefSalary EmpSalary; public clsShallow CreateShallowCopy(clsShallow inputcls) { return (clsShallow)inputcls.MemberwiseClone(); } } public class clsRefSalary { public clsRefSalary(int _salary) { Salary = _salary; } public int Salary; }
再看如何调用:
static void Main() { // Creates an instance of clsShallow and assign values to its fields. clsShallow objshallow = new clsShallow(); objshallow.Age = 25; objshallow.EmployeeName = "Ahmed Eid"; // add the ref value to the objshallow clsRefSalary clsref = new clsRefSalary(1000); objshallow.EmpSalary = clsref; // Performs a shallow copy of m1 and assign it to m2. clsShallow m2 = objshallow.CreateShallowCopy(objshallow); m2.Age = 20; m2.EmployeeName = "jay"; // then modify the clsref salary value to be 2000 clsref.Salary = 2000; // so the m1 object salary value become 2000 Console.WriteLine(m2 == objshallow); Console.WriteLine(objshallow.EmpSalary.Salary); Console.WriteLine(m2.EmpSalary.Salary); Console.WriteLine(objshallow.Age); Console.WriteLine(m2.Age); Console.WriteLine(objshallow.EmployeeName); Console.WriteLine(m2.EmployeeName); }
最后看运行结果:
根据结果我们进行分析:
浅拷贝:
1、浅拷贝创建了类的一个新实例。(由对象的同一性得知:如果两个引用如m2 、 objshallow指向同一个对象的实例,则(m2 == objshallow)为true,而结果显示为 false,所以m2 和objshallow分别指向不同的实例,而objshallow引用所指向的实例是新创建的。
2、对于对象(clsShallow)中的引用类型成员(clsRefSalary),引用被复制,但引用的实例没有被复制,即新创建实例中的引用成员(m2.EmpSalary)等于原实例的引用成员(objshallow.EmpSalary)。 因为改变 clsref.Salary 等于2000后,objshallow.EmpSalary 和m2.EmpSalary的Salary都改变了。其实可通过Console.WriteLine(objshallow.EmpSalary == m2.EmpSalary) 输出为true来解释。
3、值类型字段逐位复制到新实例。即改变m2.Age不影响objshallow.Age值。有人要问,string 为引用类型,为什么改变m2.EmployeeName = "jay"而objshallow.EmployeeName = "Ahmed Eid"没变呢?这是因为:字符串具有恒等性,一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。
二、 深拷贝:
修改代码如下:
static void Main() { clsDeep objdeep = new clsDeep(); objdeep.Age = 25; objdeep.EmployeeName = "Ahmed Eid"; // add the ref value clsRefSalary clsref = new clsRefSalary(1000); objdeep.EmpSalary = clsref; // Performs a shallow copy of m1 and assign it to m2. clsDeep m2 = objdeep.CreateDeepCopy(objdeep); // then modify the clsref salary value to be 2000 clsref.Salary = 2000; // so the m1 object salary value become 2000 int EmpSalary = objdeep.EmpSalary.Salary; m2.Age = 20; m2.EmployeeName = "jay"; // then modify the clsref salary value to be 2000 clsref.Salary = 2000; // so the m1 object salary value become 2000 Console.WriteLine(m2 == objdeep); Console.WriteLine(objdeep.EmpSalary.Salary); Console.WriteLine(m2.EmpSalary.Salary); Console.WriteLine(objdeep.EmpSalary == m2.EmpSalary); Console.WriteLine(objdeep.Age); Console.WriteLine(m2.Age); Console.WriteLine(objdeep.EmployeeName); Console.WriteLine(m2.EmployeeName); } [Serializable] // serialize the classes in case of deep copy public class clsDeep { public static string CompanyName = "My Company"; public int Age; public string EmployeeName; public clsRefSalary EmpSalary; public clsDeep CreateDeepCopy(clsDeep inputcls) { MemoryStream m = new MemoryStream(); BinaryFormatter b = new BinaryFormatter(); b.Serialize(m, inputcls); m.Position = 0; return (clsDeep)b.Deserialize(m); } } [Serializable] public class clsRefSalary { public clsRefSalary(int _salary) { Salary = _salary; } public int Salary; }
记得加命名空间
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
查看结果:
深拷贝:
1、深拷贝创建了类的一个新实例
2、对于实例中的引用类型成员,创建引用类型成员对象的新副本。 ( objshallow.EmpSalary != m2.EmpSalary)
3、值类型字段逐位复制到新实例。
其实,浅拷贝和深拷贝的本质区别是实例中的引用类型成员如何拷贝, 浅拷贝复制引用,深拷贝创建新实例。
注:无论浅、深拷贝,静态成员都不会复制,因为静态成员属于类成员。
三 、深复制方法
/// <summary> /// Perform a deep Copy of the object. /// </summary> /// <typeparam name="T">The type of object being copied.</typeparam> /// <param name="source">The object instance to copy.</param> /// <returns>The copied object.</returns> public static T Clone<T>(this T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("The type must be serializable.", "source"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } IFormatter formatter = new BinaryFormatter(); Stream stream = new MemoryStream(); using (stream) { formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(stream); } }
摘自:http://www.codeproject.com/Articles/28952/Shallow-Copy-vs-Deep-Copy-in-NET
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?