list拷贝踩坑记录

最近做项目中,有一个场景需要复制list给其他对象的属性赋值,然后再去根据对象的其他属性操作list的元素数据,其实就是一个list的拷贝问题

代码还原

一个list集合,元素类型为class,复制一下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

连带着以前的一起改了,这可不是我们想要的结果。所以这种复制算浅克隆。

如何连元素一起复制(深克隆)

  1. 手动复制,foreach 循环 new对象手动插入新的list
  2. 第三方工具 automapper等
  3. 序列化和反序列化,通过将对象序列化为一个字节流,然后再反序列化回来,可以实现深克隆
  4. 表达式树或者反射,代码如下
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();
}

总结

以前由于经常做类似的,理解还是很清楚,好久不做到了现在一下就踩坑了,所以为了以后不继续踩坑,决定记录下来。

posted @ 2024-11-05 23:08  果小天  阅读(144)  评论(0编辑  收藏  举报