值拷貝
定義:直接復制變量的值,適用于基本數據類型(如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();