C# 浅克隆与深克隆 / 浅拷贝与深拷贝
浅克隆/浅拷贝
1、概念理解
是指将对象中的所有字段逐字复杂到一个新对象
对值类型字段只是简单的拷贝一个副本到目标对象,改变目标对象中值类型字段的值不会反映到原始对象中,因为拷贝的是副本。
对引用类型字段则是指拷贝他的一个引用到目标对象。改变目标对象中引用类型字段的值它将反映到原始对象中,因为拷贝的是指向堆是上的一个地址。

自己理解:
值类型,直接复制值
引用类型,浅克隆 只复制了 引用类型 的引用地址 。如果堆的发生变化(被复制的引用类型数据变动)也会跟着变动。
2、方法:
(1) MemberwiseClone
public class Address
{
public string City { get; set; }
public string State { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Residence { get; set; }
public Person Clone()
{
return (Person)this.MemberwiseClone();
}
}
class Program
{
static void Main(string[] args)
{
// 生成原对象
Person person1 = new Person
{
Name = "John",
Age = 30,
Residence = new Address { City = "New York", State = "NY" }
};
Person person4 = person1.Clone();
Console.WriteLine("Original: " + person1.Name + ", " + person1.Age + ", " + person1.Residence.City);
//Original: John, 30, New York
person1.Age = 99;//值类型
person1.Residence.City = "China";// 引用类型
Console.WriteLine("Copy (MemberwiseClone): " + person4.Name + ", " + person4.Age + ", " + person4.Residence.City);
//Copy (MemberwiseClone): John, 30, China
}
}
person1.Residence.City 引用类型变动 对应浅克隆 数据变动
(2) 构造函数
public class Address
{
public string City { get; set; }
public string State { get; set; }
public Address() { }
public Address(Address original)
{
this.City = original.City;
this.State = original.State;
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Residence { get; set; }
public Person() { }
public Person(Person original)
{
this.Name = original.Name;
this.Age = original.Age;
this.Residence = new Address(original.Residence);
}
}
class Program
{
static void Main(string[] args)
{
// 生成原数据
Person person2 = new Person
{
Name = "Jane",
Age = 25,
Residence = new Address { City = "San Francisco", State = "CA" }
};
Person person3 = new Person(person2);
Console.WriteLine("Original: " + person2.Name + ", " + person2.Age + ", " + person2.Residence.State);
//Original: Jane, 25, CA
person2.Age = 99;//值类型
person2.Residence.State = "Ha ha";// 引用类型
Console.WriteLine("Copy (构造函数): " + person3.Name + ", " + person2.Age + ", " + person2.Residence.State);
//Copy (构造函数): Jane, 99, Ha ha
}
}
person1.Residence.State 引用类型变动 对应浅克隆 数据变动
深克隆/深拷贝
1、概念理解
深拷贝与浅拷贝不同的是对于引用字段的处理,深拷贝将会在新对象中创建一个新的对象和原始对象中对应字段相同(内容相同)的字段,也就是说这个引用和原始对象的引用是不同, 我们改变新对象中这个字段的时候是不会影响到原始对象中对应字段的内容。
自己理解:
值类型,直接复制值
引用类型,全新对象
2、方法:
(1)手动赋值
public class Address
{
public string City { get; set; }
public string State { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Residence { get; set; }
//手动赋值
public Person DeepCopy()
{
return new Person
{
Name = this.Name,
Age = this.Age,
Residence = new Address
{
City = this.Residence.City,
State = this.Residence.State
}
};
}
}
class Program
{
static void Main(string[] args)
{
// 生成原数据
Person originalPerson = new Person
{
Name = "John",
Age = 30,
Residence = new Address { City = "New York", State = "NY" }
};
Person clonedPerson = originalPerson.DeepCopy();
Console.WriteLine("Original: " + originalPerson.Name + ", " + originalPerson.Age + ", " + originalPerson.Residence.City);
//Original: John, 30, New York
originalPerson.Age = 99;//值类型
originalPerson.Residence.City = "China";// 引用类型
Console.WriteLine("DeepCopy (手动赋值): " + clonedPerson.Name + ", " + clonedPerson.Age + ", " + clonedPerson.Residence.City);
//DeepCopy (手动赋值): John, 30, New York
}
}
person1.Residence.City 引用类型变动 对应深克隆 数据不变动
(2) JSON 序列化和反序列化
public class Address
{
public string City { get; set; }
public string State { get; set; }
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Residence { get; set; }
//手动赋值
public Person DeepCopy()
{
return new Person
{
Name = this.Name,
Age = this.Age,
Residence = new Address
{
City = this.Residence.City,
State = this.Residence.State
}
};
}
}
public static class JsonCloner
{
public static T DeepCopy<T>(T original)
{
// 检查类型是否可序列化 必须要有 [Serializable] 特性
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", nameof(original));
}
// 如果对象为 null,则返回 null
if (ReferenceEquals(original, null))
{
return default(T);
}
string json = JsonSerializer.Serialize(original);
return JsonSerializer.Deserialize<T>(json);
}
}
class Program
{
static void Main(string[] args)
{
// 生成原数据
Person originalPerson = new Person
{
Name = "John",
Age = 30,
Residence = new Address { City = "New York", State = "NY" }
};
Person clonedPerson = JsonCloner.DeepCopy(originalPerson);
Console.WriteLine("Original: " + originalPerson.Name + ", " + originalPerson.Age + ", " + originalPerson.Residence.City);
//Original: John, 30, New York
originalPerson.Age = 99;//值类型
originalPerson.Residence.City = "Shanghai";// 引用类型
Console.WriteLine("DeepCopy (Json序列化): " + clonedPerson.Name + ", " + clonedPerson.Age + ", " + clonedPerson.Residence.City);
//DeepCopy (Json序列化): John, 30, New York
}
}
person1.Residence.City 引用类型变动 对应深克隆 数据不变动
(3)二进制序列化和反序列化
[Serializable]
public class Address
{
public string City { get; set; }
public string State { get; set; }
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Residence { get; set; }
//手动赋值
public Person DeepCopy()
{
return new Person
{
Name = this.Name,
Age = this.Age,
Residence = new Address
{
City = this.Residence.City,
State = this.Residence.State
}
};
}
}
public static class BinaryCloner
{
public static T DeepCopy<T>(T original)
{
// 检查类型是否可序列化
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", nameof(original));
}
// 如果对象为 null,则返回 null
if (ReferenceEquals(original, null))
{
return default(T);
}
// 创建一个二进制序列化器
IFormatter formatter = new BinaryFormatter();
// 创建一个内存流
using (MemoryStream stream = new MemoryStream())
{
// 使用二进制序列化将对象写入内存流
formatter.Serialize(stream, original);
// 将内存流位置重置为开头
stream.Seek(0, SeekOrigin.Begin);
// 使用反序列化从内存流中读取并返回克隆的对象
return (T)formatter.Deserialize(stream);
}
}
}
class Program
{
static void Main(string[] args)
{
// 生成原数据
Person originalPerson = new Person
{
Name = "John",
Age = 30,
Residence = new Address { City = "New York", State = "NY" }
};
Person clonedPerson = BinaryCloner.DeepCopy(originalPerson);
Console.WriteLine("Original: " + originalPerson.Name + ", " + originalPerson.Age + ", " + originalPerson.Residence.City);
//Original: John, 30, New York
originalPerson.Age = 99;//值类型
originalPerson.Residence.City = "Shanghai";// 引用类型
Console.WriteLine("DeepCopy (二进制序列化): " + clonedPerson.Name + ", " + clonedPerson.Age + ", " + clonedPerson.Residence.City);
//DeepCopy (二进制序列化): John, 30, New York
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)