在类层次结构中实现ICloneable的正确方式是什么?假设我有一个抽象类DrawingObject。另一个抽象类RectangularObject继承自DrawingObject。然后还有多个具体的类,如Shape、Text、Circle等,它们都继承自RectangularObject。我想在DrawingObject上实现ICloneable,然后在层次结构中向下携带它,在每一层复制可用的属性,并在下一层调用父代的Clone。
但是问题是,由于前两个类是抽象的,所以我不能在Clone()方法中创建它们的对象。因此,我必须在每个具体的类中复制属性复制过程。还是有更好的方法?
发布于 2014-01-15 00:54:20
您可以使用object的受保护方法MemberwiseClone轻松创建一个表面上的克隆。
示例:
public abstract class AbstractCloneable : ICloneable
{
public object Clone()
{
return this.MemberwiseClone();
}
}如果你不需要像深度拷贝这样的东西,你就不需要在子类中做任何事情。
MemberwiseClone方法通过创建一个新对象,然后将当前对象的非静态字段复制到新对象来创建浅层副本。如果字段是值类型,则执行该字段的逐位复制。如果字段是引用类型,则复制引用,但不复制引用的对象;因此,原始对象及其克隆引用同一对象。
如果您在克隆逻辑中需要更多的智能,您可以添加一个虚拟方法来处理引用:
public abstract class AbstractCloneable : ICloneable
{
public object Clone()
{
var clone = (AbstractCloneable) this.MemberwiseClone();
HandleCloned(clone);
return clone;
}
protected virtual void HandleCloned(AbstractCloneable clone)
{
//Nothing particular in the base class, but maybe useful for children.
//Not abstract so children may not implement this if they don't need to.
}
}
public class ConcreteCloneable : AbstractCloneable
{
protected override void HandleCloned(AbstractCloneable clone)
{
//Get whathever magic a base class could have implemented.
base.HandleCloned(clone);
//Clone is of the current type.
ConcreteCloneable obj = (ConcreteCloneable) clone;
//Here you have a superficial copy of "this". You can do whathever
//specific task you need to do.
//e.g.:
obj.SomeReferencedProperty = this.SomeReferencedProperty.Clone();
}
}发布于 2014-01-14 23:05:16
为基类提供一个受保护的、可重写的CreateClone()方法,该方法创建当前类的新(空)实例。然后让基类的Clone()方法调用该方法,以多态方式实例化一个新实例,然后基类可以将其字段值复制到该实例中。
派生的非抽象类可以重写CreateClone()方法来实例化相应的类,并且所有引入新字段的派生类都可以重写Clone(),以便在调用继承版本的Clone()之后将其附加字段值复制到新实例中。
public CloneableBase : ICloneable
{
protected abstract CloneableBase CreateClone();
public virtual object Clone()
{
CloneableBase clone = CreateClone();
clone.MyFirstProperty = this.MyFirstProperty;
return clone;
}
public int MyFirstProperty { get; set; }
}
public class CloneableChild : CloneableBase
{
protected override CloneableBase CreateClone()
{
return new CloneableChild();
}
public override object Clone()
{
CloneableChild clone = (CloneableChild)base.Clone();
clone.MySecondProperty = this.MySecondProperty;
return clone;
}
public int MySecondProperty { get; set; }
}如果您想跳过第一个覆盖步骤(至少在默认情况下),您还可以假设一个默认的构造函数签名(例如,无参数),并尝试使用该构造函数签名和反射实例化一个克隆实例。这样,只有构造函数与默认签名不匹配的类才必须覆盖CreateClone()。
默认CreateClone()实现的一个非常简单的版本可能如下所示:
protected virtual CloneableBase CreateClone()
{
return (CloneableBase)Activator.CreateInstance(GetType());
}发布于 2018-07-08 23:31:52
我相信我比@johnny5的优秀答案有了改进。只需在所有类和基类中定义复制构造函数,在Clone方法中使用反射来查找复制构造函数并执行它。我认为这稍微更干净一些,因为你不需要一堆处理克隆重写,也不需要MemberwiseClone(),因为在很多情况下,这只是一种过于生硬的工具。
public abstract class AbstractCloneable : ICloneable
{
public int BaseValue { get; set; }
protected AbstractCloneable()
{
BaseValue = 1;
}
protected AbstractCloneable(AbstractCloneable d)
{
BaseValue = d.BaseValue;
}
public object Clone()
{
var clone = ObjectSupport.CloneFromCopyConstructor(this);
if(clone == null)throw new ApplicationException("Hey Dude, you didn't define a copy constructor");
return clone;
}
}
public class ConcreteCloneable : AbstractCloneable
{
public int DerivedValue { get; set; }
public ConcreteCloneable()
{
DerivedValue = 2;
}
public ConcreteCloneable(ConcreteCloneable d)
: base(d)
{
DerivedValue = d.DerivedValue;
}
}
public class ObjectSupport
{
public static object CloneFromCopyConstructor(System.Object d)
{
if (d != null)
{
Type t = d.GetType();
foreach (ConstructorInfo ci in t.GetConstructors())
{
ParameterInfo[] pi = ci.GetParameters();
if (pi.Length == 1 && pi[0].ParameterType == t)
{
return ci.Invoke(new object[] { d });
}
}
}
return null;
}
}最后,让我直言不讳地支持ICloneable。如果你使用这个接口,你会受到样式规则的打击,因为.NET框架设计指南说不要实现它,因为引用指南的话说,“当使用一个用ICloneable实现类型的对象时,你永远不知道你会得到什么。这使得这个接口变得毫无用处。”这意味着你不知道你得到的是深拷贝还是浅拷贝。这简直就是诡辩。这是否意味着永远不应该使用复制构造函数,因为“你永远不知道你会得到什么”?当然不是。如果你不知道你会得到什么,这只是类设计的问题,而不是接口的问题。
https://stackoverflow.com/questions/21116554
复制相似问题