将列表复制到其他列表中

时间:2015-12-11 19:51:47

标签: c# list

我知道这是多次被问到的,我正在尝试实现它。我有以下列表

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 {});

我不知道在上面的那些花括号内输入什么。

2 个答案:

答案 0 :(得分:10)

  

如果在主列表中更改了某些内容,则不希望内容在克隆列表中更改。

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

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

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();

但请注意:

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

要考虑的选项:

  • DeepClone()添加GenList方法,将逻辑保存在一个地方,但很多地方都需要它。
  • 添加构造函数:GenList(GenList)正确复制
  • 使用不可变类型(例如make GenList immutable),此时集合的浅克隆就足够了。

答案 1 :(得分:2)

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

[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);
    }
}