将列表复制到其他列表中
本文关键字:列表 其他 复制 | 更新日期: 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);
}
}