Reputation: 1039
Given a tree hierarchy, suppose it is the following:
abstract class Person : ICloneable
...
sealed class Student : Person
...
I want to implement the ICloneable interface. In the Student.Clone method I wish to do something like:
{
Student clonedStudent = base.Clone() as Student;
clonedStudent.x1 = this.x1;
return clonedStudent
}
Because Person is abstract I can't create a Person in the Person.Clone() method, so I can't return a cloned Person, so I can't clone a Person.
The best answer I have figured out is to overload the Clone() method in the Person class to receive a Person, clone and return it. Then in the Student.Clone implementation call this overload to clone the person's related fields. Something like this:
//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
}
Of course if any of the above class required to build any logic in its constructors this solution is more than useless. Any idea to implement a better one?
I think this is a subproblem of a more general one, so the answer will fit very well into a large superset.
Upvotes: 3
Views: 1531
Reputation: 471
Since your Student class inherits the properties/fields from the base class (Person), it is not necessary to clone the person object.
The solution is to not implement the Clone() method within the abstract base class, but instead make it abstract and force the implementation in any sub-classes which inherit from it. In order to clone, you can simply instantiate a new instance of the Student class and populate the base properties using a clone constructor. See my example. I'm not sure if this helps in any way.
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;
}
}
Upvotes: 2