如何克隆继承的对象?

发布于 2024-09-17 23:29:16 字数 1601 浏览 7 评论 0原文

我有一个具有此方法的 Tile 类:

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

以及另一个继承自 Tile 的类 Checker

我还有一个 Board 类,它是一个 List。我想克隆板,所以我写了这个:

    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 code> 也复制子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 构造函数如下所示:

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

I've got a Tile class with this method:

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

And another class Checker that inherits from Tile.

I also have a Board class that is a List<Tile>. I want to clone the board, so I wrote this:

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

But it throws an error:

cannot convert from 'object' to 'Checkers.Tile'

Now I can make the Tile.Clone method return a Tile instead, but then will the MemberwiseClone copy the additional properties in the sub-Checker as well?


If that's not the problem, what's the semantic difference between the above Board.Clone method and this?

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

Because they're definitely having different effects on my program, even though when I print the board it looks the same. I don't think something is being cloned but a reference is being returned. The Board ctor looks like this:

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

The Tile class actually doesn't have any properties. The checker just has two enums properties:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧话新听 2024-09-24 23:29:16

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


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

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

当然,只有当您的图块(或跳棋)包含具有引用类型的字段时,这才会产生影响。

Yes, MemberwiseClone will also copy the Checker-only fields. MemberwiseClone cannot know the return type of your Clone method; therefore, it's behaviour cannot depend on it.


About the difference betweeen your Clone implementation and the serialization: MemberwiseClone creates a shallow copy of the Tiles: If a Tile (or Checker) references some object, the Tile's clone still references the same object (rather than a copy of it).

On the other hand, your serialization code is a well known practice for creating a deep copy of your board: The whole tree of dependent objects is serialized and deserialized.

Of course, this only makes a difference if your Tiles (or Checkers) contain fields with reference types.

宣告ˉ结束 2024-09-24 23:29:16

在我看来,关于克隆,有四种主要的对象类别:

  1. 那些在不破坏某些东西的情况下无法克隆的对象
  2. 那些没有公开承诺可克隆性,但可以使用 MemberwiseClone 很好地克隆的
  3. 对象 那些没有公开承诺可克隆性的对象,但可以通过 MemberwiseClone 之外的其他方式进行克隆
  4. 那些代表自身和派生类公开宣传可克隆性的方法。

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.

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

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

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.

谎言月老 2024-09-24 23:29:16

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

Yes, it will - it's polymorphism.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文