c#中的对象大体分为值类型和引用类型,值类型大致包括 int, struct等,引用类型大致包括 自定义Class,object 等。string属于特殊的引用类型,不在本文的讨论之内。
值类型直接存储对象,而引用类型存储对象的地址,在对引用类型进行复制的时候,也只是复制对象的地址。
完全复制一个引用类型对象主要有几种方法:
1.添加一个Copy函数,进行拷贝(如果字段为引用类型,需要循环添加Copy函数,这样情况会变的十分复杂。)
namespace ConsoleApplication1 { class User { public string Name { get; set; } public string Sex { get; set; } public House Home { get; set; } public User Copy() { User newUser = (User)this.MemberwiseClone(); newUser.Home = this.Home.Copy(); return newUser; } } class House { public string Address { get; set; } public House Copy() { return (House)this.MemberwiseClone(); } } class Program { static void Main(string[] args) { User a = new User(); a.Name = "A"; a.Home = new House() { Address = "长江路" }; User b = a.Copy(); b.Name = "B"; b.Home.Address = "黄河路"; Console.WriteLine(a.Name); Console.WriteLine(a.Home.Address); Console.ReadLine(); } } }
2.利用序列化反序列化(对性能会有杀伤)
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading.Tasks; namespace Test { class Program { static void Main(string[] args) { Test t1 = new Test(); Console.WriteLine(t1.list.Count); Test t2 = (Test)Clone(t1); t2.list.Add(""); Console.WriteLine(t2.list.Count); Console.WriteLine(t1.list.Count); Console.ReadLine(); } public static object Clone(object obj) { BinaryFormatter bf = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); bf.Serialize(ms, obj); ms.Position = 0; return (bf.Deserialize(ms)); ; } } [Serializable] public class Test { public List<string> list = new List<string>(); } }
3.利用反射(测试了一个网上的接口可用,但是对性能杀伤和序列化反序列化相当,而且可能对代码混淆有一定影响。 https://www.cnblogs.com/zhili/p/DeepCopy.html)
最后附上微软文档:
https://docs.microsoft.com/zh-cn/dotnet/api/system.object.memberwiseclone?redirectedfrom=MSDN&view=netframework-4.7.2#System_Object_MemberwiseClone