Как клонировать унаследованный объект? - PullRequest
2 голосов
/ 06 сентября 2010

У меня есть 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 возвращать 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);
        }
    }

Поскольку они определенно влияют на мою программу, даже когда я печатаюдоска это выглядит то же самое.Я не думаю, что что-то клонируется 1034 *, но возвращается ссылка.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 ]

3 голосов
/ 06 сентября 2010

Да, MemberwiseClone также будет копировать поля Checker только. MemberwiseClone не может знать тип возврата вашего Clone метода; следовательно, его поведение не может зависеть от него.


О разнице между вашей реализацией Clone и сериализацией: MemberwiseClone создает поверхностную копию тайлов: если тайл (или средство проверки) ссылается на некоторый объект, клон тайла по-прежнему ссылается на тот же объект (а не его копия).

С другой стороны, ваш код сериализации - это хорошо известная практика для создания глубокой копии вашей доски: все дерево зависимых объектов сериализуется и десериализуется.

Конечно, это имеет значение, только если ваши плитки (или шашки) содержат поля со ссылочными типами.

2 голосов
/ 17 октября 2010

На мой взгляд, существует четыре основных класса объектов в отношении клонирования:

  1. Те, которые нельзя клонировать, не нарушая чего-либо
  2. Те, которые не дают публичного обещания клонируемости, но могут бытьприятно клонируется с использованием MemberwiseClone
  3. Те, которые не дают публичного обещания клонирования, но могут быть клонированы с помощью других средств, кроме MemberwiseClone
  4. Те, которые публично рекламируют клонируемость от своего имени и производных классов.
К сожалению, обычно нетхороший способ различить # 1 и # 2, если тип не скрывает метод MemberwiseClone.Мне нравится называть тип № 3 полуклонируемым.

Полуклонируемый объект должен поддерживать защищенный виртуальный метод, называемый чем-то вроде CloneBase, который будет возвращать либо объект, либо тип базового класса (это не имеет значениямного на практике);метод CloneBase самого низкого уровня должен вызывать MemberwiseClone и делать все необходимое для исправления клонированного объекта.Любой производный класс, который поддерживает клонирование, должен иметь открытый метод Clone, который просто вызывает CloneBase и типизирует результат.Любая логика производного класса, необходимая для исправления и объекта после клонирования на уровне базового класса, должна переопределять CloneBase.

Если может возникнуть необходимость в производном классе, который не поддерживает клонирование, тогдаpublic полуклонируемый класс и наследовать от этого класса CloneableWhh, который ничего не делает, кроме добавления общедоступного метода Clone.Таким образом, неклонируемые классы могут быть производными от полуклонируемых классов, а клонируемые классы могут быть производными от CloneableWhothing.

1 голос
/ 06 сентября 2010

Да, это будет - это полиморфизм .

...