如何克隆继承的对象?

时间:2010-09-05 21:56:09

标签: c# cloning

我使用此方法获得Tile课程:

    public object Clone()
    {
        return MemberwiseClone();
    }

另一个继承自Checker

的班级Tile

我还有一个BoardList<Tile>。我想克隆电路板,所以我写了这个:

    public Board Clone()
    {
        var b = new Board(width, height);
        foreach (var t in this) b.Add(t.Clone());
        return b;
    }

但它引发了一个错误:

  

无法从'object'转换为'Checkers.Tile'

现在我可以让Tile.Clone方法改为Tile,但MemberwiseClone还会复制子Checker中的其他属性吗?


如果这不是问题,那么上述Board.Clone方法与此之间的语义差异是什么?

    public Board Clone()
    {
        using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, this);
            ms.Position = 0;
            return (Board)bf.Deserialize(ms);
        }
    }

因为它们对我的程序肯定会产生不同的影响,即使我在打印电路板时看起来也是如此。我不认为某些东西是克隆但是正在返回引用。 Board ctor看起来像这样:

    public Board(int width = 8, int height = 8)
    {
        this.width = width;
        this.height = height;
        this.rowWidth = width / 2;
        this.Capacity = rowWidth * height;
    }

Tile类实际上没有任何属性。检查器只有两个枚举属性:

public enum Color { Black, White };
public enum Class { Man, King };

public class Checker : Tile
{
    public Color Color { get; set; }
    public Class Class { get; set; }

3 个答案:

答案 0 :(得分:3)

是的,MemberwiseClone也会复制Checker - 仅限字段。 MemberwiseClone无法知道Clone方法的返回类型;因此,它的行为不能依赖它。


关于Clone实现与序列化之间的区别:MemberwiseClone创建Tiles的浅层副本:如果Tile(或Checker)引用了某个对象,则Tile的克隆仍然引用相同的对象(而不是它的副本)。

另一方面,序列化代码是well known practice,用于创建电路板的深层复制:整个依赖对象树被序列化和反序列化。

当然,如果您的Tiles(或Checkers)包含带引用类型的字段,这只会产生影响。

答案 1 :(得分:2)

正如我所看到的,关于克隆,有四个主要类别的对象:

  1. 那些在不破坏的情况下无法克隆的对象
  2. 克隆性的公开承诺,但可以使用MemberwiseClone很好地克隆
  3. 那些没有公开承诺可克隆性,但可以通过除MemberwiseClone之外的其他方式克隆的那些
  4. 那些公开宣传克隆性的代表自己和派生类。
不幸的是,除非类型模糊了MemberwiseClone方法,否则通常没有很好的方法来区分#1和#2。我喜欢将类型#3称为半可复制的。

半可复制对象应该支持一个名为CloneBase的受保护虚拟方法,该方法将返回Object或基类类型(实际上并不重要);最低级别的CloneBase方法应调用MemberwiseClone并执行修复克隆对象所需的任何操作。任何支持克隆的派生类都应该有一个公共的Clone方法,它只调用CloneBase并对结果进行类型转换。在基类级别克隆之后修复和对象所需的任何派生类逻辑都应该覆盖CloneBase。

如果可能需要不支持克隆的派生类,则将public设为半可克隆类,并从该类继承CloneableWhatever除了添加公共Clone方法之外什么也不做。这样,非可克隆类可以从半可克隆类派生,可克隆类可以从CloneableWhatever派生。

答案 2 :(得分:1)

是的,它会 - polymorphism