- A+
所属分类:.NET技术
最近做项目中,有一个场景需要复制list给其他对象的属性赋值,然后再去根据对象的其他属性操作list的元素数据,其实就是一个list的拷贝问题
代码还原
一个list
internal class Program { static void Main(string[] args) { Console.WriteLine("Hello, World!"); var lista = new List<People>(); lista.Add(new People() { Name = "LaoWang", Age= 1 }); lista.Add(new People() { Name = "LaoLi", Age = 2 }); lista.Add(new People() { Name = "LaoZhang", Age = 3 }); var listb = new List<People>(lista); listb.Add(new People() { Name = "LaoLiu", Age = 4 }); Console.WriteLine("lista:"); foreach (var item in lista) { Console.WriteLine(item.Name); Console.WriteLine(item.Age); } Console.WriteLine(" "); Console.WriteLine("listb:"); foreach (var item in listb) { Console.WriteLine(item.Name); Console.WriteLine(item.Age); } } } public record People { public string Name { get; set; } public int Age { get; set; } }
输出结果:
Hello, World! lista: LaoWang 1 LaoLi 2 LaoZhang 3 listb: LaoWang 1 LaoLi 2 LaoZhang 3 LaoLiu 4
增加了元素,表面上是没有什么影响的,但是如果我修改呢:
foreach (var item in listb) { item.Name = "DDl"; item.Age = 8; } Console.WriteLine("new lista:"); foreach (var item in lista) { Console.WriteLine(item.Name); Console.WriteLine(item.Age); } Console.WriteLine(" "); Console.WriteLine("new listb:"); foreach (var item in listb) { Console.WriteLine(item.Name); Console.WriteLine(item.Age); }
结果变成了:
new lista: DDl 8 DDl 8 DDl 8 new listb: DDl 8 DDl 8 DDl 8 DDl 8
连带着以前的一起改了,这可不是我们想要的结果。所以这种复制算浅克隆。
如何连元素一起复制(深克隆)
- 手动复制,foreach 循环 new对象手动插入新的list
- 第三方工具 automapper等
- 序列化和反序列化,通过将对象序列化为一个字节流,然后再反序列化回来,可以实现深克隆
- 表达式树或者反射,代码如下
public static T DeepClone<T>(T obj) { using (var ms = new MemoryStream()) { var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); formatter.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(ms); } } public static List<T> DeepCloneList<T>(List<T> list) { return list.Select(item => DeepClone(item)).ToList(); }
总结
以前由于经常做类似的,理解还是很清楚,好久不做到了现在一下就踩坑了,所以为了以后不继续踩坑,决定记录下来。