【问题标题】:How to deep copy a matrix in C#?如何在 C# 中深度复制矩阵?
【发布时间】:2011-11-22 15:30:32
【问题描述】:

我有一个List<List<CustomClass>>,其中CustomClass 是一个引用类型。

我需要将此矩阵的完整深层副本制作成一个新的。由于我想要一个深拷贝,因此矩阵中的每个 CustomClass 对象都必须复制到新矩阵中。

您将如何以有效的方式做到这一点?

【问题讨论】:

  • 您的 CustomClass 是否已经实现了 ICloneable 或者它是否已经具有 .Clone 方法?
  • 假设CustomClass 被标记为ISerializable,您可以通过序列化和反序列化对象,用很少的代码获得深度克隆。不确定它是否符合您的“高效”标记,所以我将其作为评论留下。
  • @Davide Piras:CustomClass 尚未实现 ICloneable,但实现它不会有问题。因此,我会接受使用 ICloneable 的解决方案。

标签: c# performance data-structures deep-copy


【解决方案1】:

对于实现 ICloneable 的 CustomClass,这不是很困难:

var myList = new List<List<CustomClass>>();

//populate myList

var clonedList = new List<List<CustomClass>>();

//here's the beef
foreach(var sublist in myList)
{
   var newSubList = new List<CustomClass>();
   clonedList.Add(newSubList);
   foreach(var item in sublist)
      newSublist.Add((CustomClass)(item.Clone()));
}

如果您不想实现 ICloneable,您可以使用任何“DeepCopy”类型的方法以类似的方式完成这项工作(不过我建议使用内置接口)。

【讨论】:

  • 你是不是错过了 newSublist.Add(item.Clone()) 行中的演员表?
【解决方案2】:

序列化整个对象然后再次反序列化的一种更简单的方法,试试这个扩展方法:

public static T DeepClone<T>(this T source)
{
  if (!typeof(T).IsSerializable)
  {
    throw new ArgumentException("The type must be serializable.", "source");
  }

  // Don't serialize a null object, simply return the default for that object
  if (Object.ReferenceEquals(source, null))
  {
    return default(T);
  }

  IFormatter formatter = new BinaryFormatter();
  Stream stream = new MemoryStream();
  using (stream)
  {
    formatter.Serialize(stream, source);
    stream.Seek(0, SeekOrigin.Begin);
    return (T)formatter.Deserialize(stream);
  }
}

用法

List<List<CustomClass>> foobar = GetListOfListOfCustomClass();

List<List<CustomClass>> deepClonedObject = foobar.DeepClone();

【讨论】:

  • 为什么在 DeepClone 中使用双重 List
  • 这就是问题中提到的。不是吗?
  • 应该可以指定T为"this"参数的类型,然后方法就可以根据传入的变量推断泛型类型,使用更简单。跨度>
  • @KeithS 谢谢,这将使指定类型可选:) 现在更新代码
【解决方案3】:

有两种可能:

  1. 在您的 CustomClass 上实现 ICloneable 接口,然后您可以克隆您的对象。

  2. 如果类可以序列化,则将其序列化为内存流并从那里反序列化。这将创建它的副本。

我更愿意采用第一种选择,因为我认为序列化/反序列化比通过 ICloneable 克隆要慢。

【讨论】:

  • 序列化到 MemoryStream 并返回实际上并不算太糟糕。将字段逐字段克隆到新对象仍然会更快,但是您会遇到可维护性问题;每个新字段都必须在 Clone() 方法中表示。在进行各种可能的未来更改时,无需触及此类情况下的 XML 序列化。因此,我建议使用某种形式的内存序列化来实现 ICloneable。
  • @KeithS:你说得对,最后一句话只是我个人的喜好。
【解决方案4】:

假设您有一个可以复制 CustomClass 对象的 Copy 方法:

var newMatrix = oldMatrix
    .Select(subList => subList.Select(custom => Copy(custom)).ToList())
    .ToList();

【讨论】:

    猜你喜欢
    • 2012-09-22
    • 1970-01-01
    • 2017-04-15
    • 2013-12-03
    • 1970-01-01
    • 2021-01-08
    • 2015-02-28
    • 1970-01-01
    • 2012-10-24
    相关资源
    最近更新 更多