将列表复制到其他列表中

本文关键字:列表 其他 复制 | 更新日期: 2023-09-27 18:26:24

我知道这个问题被问了很多次,我正在努力实现它。我有下面的列表

internal class GenList
{
    public string Col1 { set; get; }
    public string Col2 { set; get; }
}
List<GenList> MainList = new List<GenList>();

我想将列表复制到其他列表中,并且不希望克隆列表中的内容在主列表中发生更改时发生更改。所以我正在尝试做低于

List<GenList> cloned = MainList.ConvertAll(GenList => new GenList {});

我不知道在上面这行那个些花括号里输入什么。

将列表复制到其他列表中

如果主列表中有更改,则不希望克隆列表中的内容发生更改。

基本上,这听起来像是你想要一个深度克隆。换句话说,创建一个新列表,其中每个元素都是原始列表中元素的副本,而不仅仅是对原始列表所指对象的引用。

在你的情况下,这很简单:

var cloned = MainList.ConvertAll(x => new GenList { Col1 = x.Col1, Col2 = x.Col2 });

或者使用LINQ:

var cloned = MainList.Select(x => new GenList { Col1 = x.Col1, Col2 = x.Col2 })
                     .ToList();

但请注意:

  • 如果添加新属性,则需要更改此代码
  • 如果添加可变类型的属性,则也需要克隆该属性

要考虑的选项:

  • GenList中添加一个DeepClone()方法,以将逻辑保持在一个位置,无论多个位置需要它
  • 添加一个构造函数:GenList(GenList),它适当地复制
  • 改为使用不可变类型(例如,使GenList不可变),此时集合的浅克隆就足够了

这里有一个通过序列化的快速深度克隆解决方案:

[Serializable]
public class GenList
{
    public string Col1 { set; get; }
    public string Col2 { set; get; }
    public GenList DeepClone()
    {
        using (var stream = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, this);
            stream.Position = 0; //reset stream
            var cloned = formatter.Deserialize(stream) as GenList;
            return cloned;
        }
    }

和一个测试来验证:

[TestClass]
public class DeepCloneTests
{
    [TestMethod]
    public void ReferencesAreNotMaintained()
    {
        var object1 = new GenList() { Col1 = "a", Col2 = "b" };
        var cloned = object1.DeepClone();
        Assert.AreEqual(object1.Col1, cloned.Col1);
        Assert.AreEqual(object1.Col2, cloned.Col2);
        cloned.Col1 = "c";
        cloned.Col2 = "d";
        Assert.AreNotEqual(object1.Col1, cloned.Col1);
        Assert.AreNotEqual(object1.Col2, cloned.Col2);
    }
}