Как исправить реализацию 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;
}
}