Copy constructors
Download source in attachment at the bottom.
A while ago I heard the term “copy constructor” for the first time from a C++ developer. A copy constructor is a constructor which takes a (single) parameter of an existing object of the same type as the constructor’s class. It’s used to create an deep copy of the passed object, instead of creating a shallow copy. With a shallow copy, you’d create a reference to the values of the original object, as show in the following code:
Customer cust1 = new Customer();
Customer cust2;
cust2 = cust1;
cust1.FirstName = “Dennis”;
cust1.LastName = “van der Stelt”;
Console.WriteLine(cust2.FullName);
// Outputs : Dennis van der Stelt
As you can see, we tell cust2 to be like cust1, which is what it exactly does. This is basic behavior everyone should be aware of. Even when you pass a reference type (like our Customer class) to a method by value, you’ll still only get the reference to the object.
But let’s have a look at our Customer class. A few details are worth mentioning. First the default constructor, without any parameters. I’ve included it because when we’re done, we still want to be able to create a customer object without passing anything. The second detail we’ll discuss is the BirthDate property. It immediately sets a private field with the current age of the customer. Probably better would be to calculate ones age when we retrieve this value, but for the sake of the demo we want it done this way. Last detail to look at is the FirstName property. When we request the first name, we’ll get it capitalized.
public class Customer
{
private string _firstName;
private string _lastName;
private DateTime _birthDate;
private int _age;
public Customer() { }
public string FirstName
{
get
{
string value = _firstName.Substring(0, 1).ToUpper() + _firstName.Substring(1, _firstName.Length – 1).ToLower();
value.Trim();
return value;
}
set { _firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
public DateTime BirthDate
{
get { return _birthDate; }
set
{
_birthDate = value;
_age = (DateTime.Now.Year – _birthDate.Year) – (_birthDate.AddYears(DateTime.Now.Year – _birthDate.Year) > DateTime.Now ? 1 : 0);
}
}
public string FullName
{
get { return FirstName + ” “ + LastName; }
}
public int Age
{
get { return _age; }
}
}
Imagine you’d want a copy of this customer. You can take care of this in some other class and copy all values. But you’ll get the first name of your customer capitalized, and that might not be what you want or need. And shouldn’t this functionality be in the Customer class itself? For this we create a copy constructor, as shown in the next example:
/// <summary>
/// Copy constructor, creates a deep copy of passed object.
/// </summary>
/// <param name=”customer”></param>
public Customer(Customer customer)
{
this._firstName = customer._firstName;
this._lastName = customer._lastName;
this.BirthDate = customer.BirthDate;
}
As you can see, the new constructor takes one parameter of the same type as its own class. When analyzing this constructor, we see a deep copy of the firstname and lastname fields, but not for the birthdate field.
As said, we probably want a deep copy of the firstname, so we won’t get our original firstname capitalized. This is possible, because every class can see the private members of any (instantiated) class of the same type, which is default OO behavior. So our constructor can actually see the private fields _firstName and _lastName of the passed class.However with the birthdate, we’d want to set its value through the BirthDate property. That way, the age is immediately set, which would not happen had we set the private field _birthDate.
So now we can start using our copy constructor to copy our original customer, like this:
cust2 = new Customer(cust1);
cust2.FirstName = “Laura”;
string msg = string.Format(“{0} is married to {1}”, cust1.FullName, cust2.FullName);
Console.WriteLine(msg);
So now you know what a copy constructor is and how to use it. Be careful with every copy, to select the right method, using either the fields or properties. There’s no single solution, as you can see in the above example. But if you’re not sure, it’s probably better to always use deep copies and use the private fields, instead of the properties.
Dennis, i disslike the copy ctor because a couple of reasons.
First of all, when you add an new member to the class you should also add this to your copy ctor. This is something that you can forget when you have some release stress.
When you classes are marked as serializable, you can serialize and deserialize them to create a copy. Advantage of this is that is is easy to implement and generic. A disadvantage is that everything must be serializable.
Second, why don’t you use the MemberwiseClone method? Then a subclass should implement the ICloneable interface if a shallow copy is not appropriate.
The copy constructor is less known in .NET, because the Framework has the Object.MemberwiseClone (for shallow copies) and the ICloneable interface for your own cloning operation (a deep copy if you feel like it). The latter is preferred if you do not wish to expose a public constructor.
I’m not in favor for using a constructor to deep copy an instance. One of the principles for good object modeling is the Minimum Parameter Rule, only properties and collaborations necessary for an object to exist should be passed into the object’s construction method.
Another thing is… the whole reason for using a copy constructor is the level of control you get by sitting on top of the implementation details of the Customer class and the fact that you do not want to use the derived property (FirstName). The developer implementing the copy constructor has to know both the implementation details of the object’s storage and derived properties, which is acceptable in the context of the deep clone task. A bigger problem is that every other task resulting in changes in the customer class (forces working on the derived properties) has to know about the deep clone responsibility too.
So, should the customer class be responsible for the deep clone?
Perhaps I should’ve mentioned MemberwiseClone. I don’t feel happy with the ICloneable interface, but that’s probably my problem. I know of no advantage of using that interface. And for some reason, I like the copy constructor over the Clone method.
PJ is right about the serializable part, but for me still no reason to throw away the copy constructor. Deep copies aren’t possible.
Paul and PJ both raise the concern about keeping up with the copying and adding new members/properties/whatever. Some words about it.
1. When you agree on copy constructors, you just have to make sure it’s always up to date. Some goes for some Clone() method. Exact same behavior. With good code reviews, you can pay attention to this.
2. Another rule is the single-responsibility principle. Although this probably isn’t truly part of that principle, I do believe it’s the responsibility of the class itself to be able top create either a shallow or deep copy of itself.
3. And when the Customer class changes, I don’t like some helper class to be changed as well. It’s much harder to keep track of changes in two classes, than in one class.
But of course I’m not all knowing 🙂
Dennis, I totally agree with number three. The last thing that I want is to update my helper class when my Customer class changes.
So I totally disagree with Paul Gielens, making a class smarter will raise the IQ of the total family and makes it much easier to maintain.
And for the ICloneable interface, this will be used by the MemberwiseClone method if implemented! So that is a great advantage of it.
“making a class smarter will raise the IQ of the total family and makes it much easier to maintain.”
It depends 😉 I’ve seen lots of smart unmentionable classes in my short career 😀
I’m not saying it shouldn’t be responsible… just questioning. I’m leaning towards “for the copy task responsibility” since the Customer class is the place where all the gory details live. But still I dislike the fact that if I change the internal storage I have to worry about the deep copy behavior, from a developers perspective.
“still I dislike the fact that if I change the internal storage I have to worry about the deep copy behavior, from a developers perspective”
Depends. If you want (perhaps need) deep-copy behavior I’d really want it in the specific class. Because if I need to change internals, I’ll check the class itself for 80% or 90% for sure. It’s much harder to say other classes that might do the deep-copy (is this at all possible?) will be checked and adjusted.
Another advantage of putting the deep-copy behavior in the class, is that you can read the private member values without using reflection and i geus it is the first place where i and others will look for the logic.
sorry, but that’s not deep-copying either, if firstName was a referenceType (such as a StringBuilder) it would just copy a reference to the original.
Sallow Copy – copies ValueType only (such as strings)
Deep Copy – copies ValueType and ReferenceType