Как исправить реализацию ICloneable в древовидной иерархии, основанной на абстрактном классе?

Учитывая иерархию дерева, предположим, что это следующее:

abstract class Person : ICloneable
...
sealed class Student : Person
...

Я хочу реализовать интерфейс ICloneable. В методе Student.Clone я хочу сделать что-то вроде:

{
     Student clonedStudent = base.Clone() as Student;
     clonedStudent.x1 = this.x1;
     return clonedStudent
}

Поскольку Person является абстрактным, я не могу создать Person в методе Person.Clone(), поэтому я не могу вернуть клонированного Person, поэтому я не могу клонировать Person.

Лучший ответ, который я нашел, - это перегрузить метод Clone () в классе Person, чтобы получить Person, клонировать и вернуть его. Затем в реализации Student.Clone вызовите эту перегрузку, чтобы клонировать связанные с человеком поля. Что-то вроде этого:

//In the Person class:
public abstract object Clone();
protected Person Clone(Person clonedPerson)
{
    // Clone all person's fields
    return clonedPerson:
}
//In the Student class:
public override object Clone()
{
    Student clonedStudent = base.Clone(new Student()) as Student;
    // Clone all student's fields
    return clonedStudent
}     

Конечно, если какой-либо из приведенных выше классов требуется для построения какой-либо логики в его конструкторах, это решение более чем бесполезно. Есть идеи для реализации лучшего?

Я думаю, что это подзадача более общего характера, поэтому ответ очень хорошо впишется в большой суперсет.

1 ответ

Решение

Так как ваш класс Student наследует свойства / поля от базового класса (Person), нет необходимости клонировать объект person.

Решение состоит в том, чтобы не реализовывать метод Clone() внутри абстрактного базового класса, а вместо этого сделать его абстрактным и принудительно реализовать реализацию в любых подклассах, которые наследуют его. Чтобы клонировать, вы можете просто создать новый экземпляр класса Student и заполнить базовые свойства с помощью конструктора клонов. Смотрите мой пример. Я не уверен, поможет ли это в любом случае.

class Program
    {
        static void Main(string[] args)
        {
            Student studentA = new Student(1000, "Defense Against the Dark Arts", "Harry", "Potter", 25);
            Student studentB = (Student)studentA.Clone();
        }
    }

    public abstract class Person : ICloneable
    {
        public string FirstName { get; set; }
        public string Surname { get; set; }

        private int SomePrivateVariable { get; set; }

        public Person()
        {

        }

        public Person(string firstName, string surname, int privateVariableDefault)
        {
            this.FirstName = firstName;
            this.Surname = surname;
            this.SomePrivateVariable = privateVariableDefault;
        }

        public Person(Person original)
        {
            this.FirstName = original.FirstName;
            this.Surname = original.Surname;
            this.SomePrivateVariable = original.SomePrivateVariable;
        }

        public abstract object Clone();
    }

    public sealed class Student : Person
    {
        public int StudentId { get; set; }
        public string CourseTitle { get; set; }

        public Student()
        {

        }

        //Constructor with all the fields, passed down to the base class
        public Student(int studentId, string courseTitle, string firstName, string surname, int baseVariableDefault)
            : base(firstName, surname, baseVariableDefault)
        {
            this.StudentId = studentId;
            this.CourseTitle = courseTitle;
        }

        //A clone constructor which takes an object of the same type and populates internal 
        //and base properties during construction
        public Student(Student original)
            : base(original)
        {
            this.FirstName = original.FirstName;
            this.Surname = original.Surname;
            this.StudentId = original.StudentId;
            this.CourseTitle = original.CourseTitle;
        }

        public override object Clone()
        {
            Student clone = new Student(this);    
            return clone;
        }
    }
Другие вопросы по тегам