【问题标题】:Copy/Clone all values from a List to another in a C#将所有值从列表复制/克隆到 C# 中的另一个
【发布时间】:2016-05-05 22:54:15
【问题描述】:

我有课

public class Car()
{
    public string Name;
    public string Model;
}

我有一个财产

List<Car> CarsA = new List<Car>();
CarsA.Add(new Car(){Name = "Verna",Model="Hyundai"});
CarsA.Add(new Car(){Name = "X1",Model="Bmw"});

我还有另一个财产

List<Car> CarsB = new List<Car>();

现在我想在不获取 CarsA 属性当前实例的情况下将所有条目从 CarsA 添加到 CarsB 的克隆/复制

(即我想为每个条目创建新对象并添加它)。

有点像

foreach(var car in CarsA)
{
    Car newCar =new Car();
    newCar.Name = car.Name;
    newCar.Model = car.Model;
    CarsB.Add(newCar);
}

如果我不想实现 ICloneable 并且我没有复制构造器怎么办?

【问题讨论】:

  • 这不适合您的目的吗? stackoverflow.com/questions/222598/…
  • 循环有什么问题?
  • 我的原始类中有很多属性..所以我认为必须有更好的方法来提高代码可读性
  • Deep copy of List<T>的可能重复
  • 如果你想提高可读性,只需将循环放在扩展方法中,并在任意数量的列表中调用它。

标签: c# list clone


【解决方案1】:

您或许可以考虑 LINQ 解决方案:

List<Car> CarsB = (from c in CarsA
                    let a = new Car() { Name = c.Name, Model = c.Model }
                    select a).ToList();

由于NameModelstring 类型(它是不可变的),所以这个操作是安全的。

我认为它的可读性很强。

相同但具有查询语法:

CarsB = CarsA.Select(c => new Car(){ Name = c.Name, Model = c.Model }).ToList();

注意:如果假设 Model 不是 string 而是 class,那么 a = new Car()上面的操作一定要稍微改一下 它真正克隆了模型中的所有项目(如下所示: Model = c.Model.Clone()) 而不仅仅是指它 (Model = c.Model)

【讨论】:

  • 是的,它是可读的,但我仍然必须在 LinQ 查询中编写所有属性。
  • @VivekSaurav 你是说你想要通用解决方案而不在 LINQ 中编写属性?
  • @VivekSaurav 在这种情况下,我认为扩展 IClonable 方法是最好的:stackoverflow.com/questions/222598/… 我认为这已经是通用的了。
  • 顺便说一句,您的解决方案中不会复制任何字符串。 (这没关系,因为字符串是不可变的,因此只能在新的Car 中替换,不能更改)。
  • @PeterA.Schneider 啊,我实际上正在寻找正确的词。我将“复制”与“推荐”区分开来(就像在普通课堂上发生的那样)。不确定“复制”是否是正确的技术术语。或者由于字符串是不可变的,我应该使用不同的术语?我认为“复制”是非常合适的,因为它是放在new Car() 中的全新字符串
【解决方案2】:

如果您想将您的实例序列化到JSON 进行深度复制,然后返回是您可以考虑的选项。

然而,这将需要比为所有要复制的对象实现复制方法更高的性能。但是它节省了大量编写复制方法的时间,即使它可能慢了数百倍,它仍然很快。

我用Json.net 使用类似这样的扩展方法来解决这个问题:

public static T Clone<T>(this T source)
{
    if (Object.ReferenceEquals(source, null))
        return default(T);

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}

正如 Scott Chamberlain 所指出的,这也可以通过其他类型的序列化(不需要 3rd 方库)来完成,例如 BinaryFormatter:(还请注意,在使用这种方法时,您的类必须用[Serializable] 属性)

public static T Clone<T>(this T source)
{
    if (Object.ReferenceEquals(source, null))
        return default(T);

    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(stream, source);
        stream.Position = 0;

        return (T) formatter.Deserialize(stream);
    }
}

然后用法是:

foreach(var car in CarsA)
{
    CarsB.Add(car.Clone<Car>());
}

也可以这样使用:

List<Car> CarsB = CarsA.Clone<List<Car>>();

【讨论】:

  • 你不需要第三方依赖,我经常使用这个完全相同的模式,但使用BinaryFormatter而不是JsonConvert
  • @ScottChamberlain 刚刚意识到为什么我总是以 json 方式结束,当使用 BinaryFormatter 时,你必须用 [Serializable] 标记你的类。
【解决方案3】:

简化的 Linq

var CarsB = CarsA.Cast<Car>().ToList();

Casting 的好处在于,如果你有不同的类型,它们具有相似的结构、接口等,它会将各自的元素复制为新的实例列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 2015-06-07
    • 2011-01-31
    • 2022-01-23
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多