3

我有一个Tile使用这种方法的课程:

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

另一个Checker继承自Tile.

我也有一Board堂课是List<Tile>. 我想克隆板,所以我写了这个:

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

但它会抛出一个错误:

无法从“对象”转换为“Checkers.Tile”

现在我可以让该Tile.Clone方法返回 a Tile,但是是否也会MemberwiseClone复制 sub- 中的附加属性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);
        }
    }

因为它们肯定对我的程序有不同的影响,即使当我打印板时它看起来是一样的。我不认为正在克隆某些东西,但正在返回引用。Boardctor 看起来像这样:

    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; }
4

3 回答 3

4

是的,MemberwiseClone还将复制Checker-only 字段。MemberwiseClone 无法知道您的Clone方法的返回类型;因此,它的行为不能依赖它。


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

另一方面,您的序列化代码是创建板的深层副本的众所周知的做法:依赖对象的整个树被序列化和反序列化。

当然,这只有在您的 Tiles(或 Checkers)包含具有引用类型的字段时才会有所不同。

于 2010-09-05T21:59:17.317 回答
2

As I see it, there are four main classes of object, with respect to cloning:

  1. Those which cannot be cloned without breaking something
  2. Those which make no public promise of cloneability, but can be nicely cloned using MemberwiseClone
  3. Those which make no public promise of cloneability, but can be cloned via some means other than MemberwiseClone
  4. Those which publicly advertise cloneability on behalf of themselves and derived classes.
Unfortunately, there's generally no nice way to distinguish #1 and #2 unless a type obscures the MemberwiseClone method. I like to refer to type #3 as semi-cloneable.

A semi-cloneable object should support a protected virtual method called something like CloneBase which will return either Object or the base class type (it won't matter much in practice); the lowest-level CloneBase method should call MemberwiseClone and do whatever is necessary to fix up the cloned object. Any derived class which supports cloning should have a public Clone method which simply calls CloneBase and typecasts the result. Any derived-class logic necessary to fix up and object after base-class-level cloning should go in an override of CloneBase.

If there may be any need for a derived class which does not support cloning, then make public a semi-cloneable class and inherit from that class a CloneableWhatever which does nothing except add the public Clone method. In that way, non-cloneable classes can derive from the semi-cloneable class, and cloneable ones can derive from CloneableWhatever.

于 2010-10-16T22:12:18.927 回答
1

是的,它会——它是多态性

于 2010-09-05T22:02:14.420 回答