What would be the best way to write a generic copy constructor function for my c# classes? They all inherit from an abstract base class so I could use reflection to map the properties, but I'm wondering if there's a better way?
5 Answers
A copy constructor basically means you have a single parameter, which is the object you're going to copy.
Also, do a deep copy, not a shallow copy.
If you don't know what deep and shallow copies are, then here's the deal:
Suppose you're copying a class that has a single row of integers as field.
A shallow copy would be:
public class Myclass()
{
private int[] row;
public MyClass(MyClass class)
{
this.row = class.row
}
}
deep copy is:
public class Myclass()
{
private int[] row;
public MyClass(MyClass class)
{
for(int i = 0; i<class.row.Length;i++)
{
this.row[i] = class.row[i];
}
}
}
A deep copy really gets the actuall values and puts them in a new field of the new object, whilst a shallow copy only copies the pointers.
With the shallow copy, if you set:
row[3] = 5;
And then print both rows, both prints will have 5 as value of the 4th number. With a deep copy however, only the first print will have this, since the rows don't have the same pointers.

- 2,524
- 10
- 34
- 51
-
You can use `row.clone()` as C# allows for primitive arrays to be cloned. – Kristopher Ives Apr 15 '14 at 02:43
-
5Doesn't the above code fail due to `row` never being initialized? – AnotherParker Jun 03 '14 at 01:17
Avoid reflection if you can. Each class should have the responsibility of copying its own properties, and send it further to the base method.

- 305,152
- 44
- 369
- 561

- 1,842
- 14
- 22
-
so just to clarify, it'd be best if you had a custom copy constructor on each class that explicitly mapped the properties? – lomaxx Jan 11 '09 at 23:02
-
I would. How hard is it to write? Certainly easier to read at a glance than a reflection-based method. – duffymo Jan 11 '09 at 23:07
-
-
4It's not hard to read and it's certainly easy to write, however there are maintenance issues to consider. If you add a new property to the class you need to update the copy constructor and tests which is pretty easy to forget. – lomaxx Jan 11 '09 at 23:51
-
I would disagree about updating the copy constructor. And depending on what the new property changed I'm not sure that you'd need to do more than just re-run your existing tests. Adding another get/set pair doesn't require new unit tests for each. – duffymo Jan 12 '09 at 00:40
-
how would you copy the newly added properties if you don't update the copy constructor? – lomaxx Jan 12 '09 at 01:09
You can create a shallow copy efficiently with reflection by pre-compiling it, for example with Expression
. For example, like so.
For deep copies, serialization is the most reliable approach.

- 1,026,079
- 266
- 2,566
- 2,900
Here's a constructor that I'm using. Note that this is a shallow constructor, and rather simplistic, due to the nature of my base class. Should be good enough to get you started.
public partial class LocationView : Location
{
public LocationView() {}
// base class copy constructor
public LocationView(Location value) {
Type t = typeof(Location);
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties)
{
pi.SetValue(this, pi.GetValue(value, null), null);
}
}
public Quote Quote { get; set; }
}

- 2,541
- 1
- 22
- 34
-
1One line-able: `foreach (var propertyInfo in typeof(LocationView).BaseType.GetProperties()) propertyInfo.SetValue(this, propertyInfo.GetValue(obj_to_copy_parameter, null), null);` you could also use a field initializer to only ever read GetProperties once. – Chris Marisic Dec 16 '14 at 18:34
-
3
-
See also http://stackoverflow.com/questions/14218989/best-way-to-clone-properties-of-disparate-objects I came up with a generic extension to shallow-clone common properties – B2K Dec 17 '14 at 17:42
You may reference valueinjecter and fasterflect nuget packages and use:
public class Myclass()
{
private string _property;
public MyClass(MyClass obj)
{
this.InjectFrom(obj.DeepClone());
}
}

- 94
- 5
-
1Why no upvotes? Can someone please confirm whether this works? – James Hirschorn Aug 18 '20 at 04:53