C# 从超类型克隆

C# clone from supertype

抽象超类型 Animal 有许多子类型,Cat、Dog 等。这些子类型只有一个构造函数和 Animal 中发现的虚拟方法的重写 - 即它们没有自己独有的属性或方法。 Class Zoo 有很多关于动物的参考和列表,但不知道或永远不需要知道猫、狗等。启用 Zoo 深度复制的最佳方法是什么? ,最好在 Cat、Dog 等中很少或没有新代码

如果您担心需要创建一个新的 Clone 实现,只是为了获得正确的类型(因为基 class 中 this 的类型是一个移动目标),您可以使用 Activator.CreateInstance 为覆盖 Animal:

的所有类型创建当前类型的新实例
var copy = (Animal)Activator.CreateInstance(this.GetType());

copy.HasClaws = this.HasClaws; // copy Animal properties

您需要一个无参数的构造函数才能使此 Activator.CreateInstance 调用有效。

深度克隆对象的一种快速简便的方法是将其序列化为 MemoryStream,然后将其反序列化回对象图。反序列化的副本将是一个没有引用原始对象的深度克隆图。与手动克隆对象相比,它可能需要更多的内存和 CPU 密集型,但编码工作要少得多;最终结果通常是可以接受的。

这是从 CodeProject:

中获取的一种实现
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;     

/// <span class="code-SummaryComment"><summary></span>
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// <span class="code-SummaryComment"></summary></span>
public static class ObjectCopier
{
 /// <span class="code-SummaryComment"><summary></span>
 /// Perform a deep Copy of the object.
 /// <span class="code-SummaryComment"></summary></span>
 /// <span class="code-SummaryComment"><typeparam name="T">The type of object being copied.</typeparam></span>
 /// <span class="code-SummaryComment"><param name="source">The object instance to copy.</param></span>
 /// <span class="code-SummaryComment"><returns>The copied object.</returns></span>
 public static T Clone<T>(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);
  }
 }
}

可以这样调用:

ObjectCopier.Clone(objectBeingCloned);