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 prop
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.
Avoid reflection if you can. Each class should have the responsibility of copying its own properties, and send it further to the base method.
You may reference valueinjecter and fasterflect nuget packages and use:
public class Myclass()
{
private string _property;
public MyClass(MyClass obj)
{
this.InjectFrom(obj.DeepClone());
}
}
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.
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; }
}