How to clone an inherited object?

雨燕双飞 提交于 2019-12-02 04:19:08

问题


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

回答1:


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.




回答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.




回答3:


Yes, it will - it's polymorphism.



来源:https://stackoverflow.com/questions/3647983/how-to-clone-an-inherited-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!