值拷贝
定义:直接复制变量的值,适用于基本数据类型(如int, float, char等)。在 C# 中,值类型(基本数据类型和结构体)默认使用值拷贝。
特点:创建原始值的完全独立副本,修改副本不会影响原始值
示例:
int a = 10;
int b = a; // 值拷贝
b = 20; // 修改b不会影响a
打印:
引用拷贝
定义:复制对象的引用(内存地址),不创建新对象。对于引用类型(类、接口、委托、数组等),赋值操作默认是引用拷贝。
特点:新变量和原变量指向同一个对象,修改其中任一对象都会影响另一个
示例:
class Person { public string Name; }
var person1 = new Person() { Name = "小明" };
var person2 = person1;person2.Name = "小红";
打印:
浅拷贝
定义:创建一个新的对象。如果数据是基本类型,拷贝的就是基本类型的值;如果数据是引用类型,则拷贝的就是内存地址即引用。
特点:
1、修改克隆对象中的基本类型数据不会影响原对象的基本类型数据。
2、修改克隆对象中的引用类型数据会影响原对象的值类型数据,本质上,两者的引用类型数据是同一个。
示例:
class Person : ICloneable
{public string Name;public int Id;public Address Address; // 引用类型字段public object Clone(){return this.MemberwiseClone(); // 浅拷贝}
}class Address { public string Street; }//--------------------------------------------------------Person person1 = new Person { Name = "Alice", Id = 666,Address = new Address { Street = "北京" }
};Person person2 = (Person)person1.Clone();//浅拷贝person2.Name = "Bob";
person2.Id = 123;
person2.Address.Street = "上海"; // 会影响p1的Address
打印:
深拷贝
定义:完全复制原始对象及其所有嵌套对象,创建一个独立的,全新的对象,在深拷贝中,原始对象与新对象之间没有任何共享的引用
特点:修改克隆对象中的基本类型数据或者引用类型数据都不会影响原对象的数据,它们是完全独立的。
示例:
class Person : ICloneable
{public string Name;public int Id;public Address Address; // 引用类型字段public object Clone(){Person cloned = (Person)this.MemberwiseClone();cloned.Address = new Address { Street = this.Address.Street }; // 深拷贝引用类型字段return cloned;}
}class Address { public string Street; }//--------------------------------------------------------Person person1 = new Person { Name = "Alice", Id = 666,Address = new Address { Street = "北京" }
};Person person2 = (Person)person1.Clone();//深拷贝person2.Name = "Bob";
person2.Id = 123;
person2.Address.Street = "上海";
打印:
总结
拷贝类型 | 实现方法 | 特点 | 适用场景 | 性能 |
值拷贝 | 直接赋值 | 创建完全独立副本 | 值类型(int, float, struct等) | 高 |
引用拷贝 | 直接赋值 | 共享同一对象引用 | 引用类型(class)的简单传递 | 高 |
浅拷贝 | MemberwiseClone | 复制值类型字段,共享引用类型字段 | 对象结构简单或引用字段无需独立 | 中等 |
深拷贝 | 手动实现/序列化 | 完全独立的对象图 | 复杂对象需要完全独立副本 | 较低 |
知识补充
对复杂对象使用序列化实现深拷贝
本示例使用Newtonsoft实现,也可以使用其他的序列化方法实现
using Newtonsoft.Json;
class Person : ICloneable
{public string Name;public int Id;public Address Address; // 引用类型字段public object Clone(){string json = JsonConvert.SerializeObject(this);return JsonConvert.DeserializeObject<Person>(json);}
}class Address { public string Street; }
特性 | 序列化方法 | 普通手动方法 |
---|---|---|
实现复杂度 | 简单,一行代码处理整个对象图 | 复杂,需要为每个引用类型字段手动实现 |
维护成本 | 低,对象结构变化不影响拷贝逻辑 | 高,对象结构变化需同步修改拷贝方法 |
性能 | 较低(涉及序列化/反序列化开销) | 较高(直接内存操作) |
循环引用处理 | 自动处理 | 需手动处理,否则会栈溢出 |
私有字段拷贝 | 可以拷贝私有字段 | 只能拷贝可访问字段 |
处理集合类对象的拷贝
浅拷贝
1. 使用构造函数浅拷贝
class Person
{public string Name;public int Id;
}List<Person> originalList = new List<Person> { new Person
{Name = "Alice" ,Id = 111} };List<Person> shallowCopy = new List<Person>(originalList); // 浅拷贝// 修改新集合中的元素会影响原集合
shallowCopy[0].Name = "Bob";
2. 使用 LINQ 的 ToList()/ToArray()实现浅拷贝
class Person
{public string Name;public int Id;
}List<Person> originalList = new List<Person> { new Person
{Name = "Alice" ,Id = 111} };List<Person> shallowCopy = originalList.ToList();// 浅拷贝// 修改新集合中的元素会影响原集合
shallowCopy[0].Name = "Bob";
深拷贝
手动实现
先在Person类中实现深拷贝方法
class Person : ICloneable
{public string Name;public int Id;public Address Address; // 引用类型字段public object Clone(){string json = JsonConvert.SerializeObject(this);return JsonConvert.DeserializeObject<Person>(json);}
}List<Person> originalList = new List<Person> { new Person{Name = "Alice" ,Id = 111} };List<Person> deepCopy = new List<Person>();
foreach (var data in originalList)
{deepCopy.Add((Person)data.Clone());
}deepCopy[0].Name = "Bob";
使用 LINQ + 元素拷贝
List<Person> deepCopy = originalList.Select(p => (Person)p.Clone()).ToList();