I have currently 2 different solutions for this, one with and one without the use of reflection:
1.) With a generic extension method (plus reflection) you can do it this way in C#:
public static class Extension
{
public static T CreateCopy<T>(this T src)
where T: new()
{
if (src == null) return default(T); // just return null
T tgt = new T(); // create new instance
// then copy all properties
foreach (var pS in src.GetType().GetProperties())
{
foreach (var pT in tgt.GetType().GetProperties())
{
if (pT.Name != pS.Name) continue;
(pT.GetSetMethod()).Invoke(tgt, new object[] {
pS.GetGetMethod().Invoke(src, null) });
}
};
return tgt;
} // method
} // class
This is very powerful, because now you can clone every object, not just objects from the classes you have written, but from all classes including the system classes of the .NET Framework. And thanks to reflection, you don't need to know its properties, they are copied automatically.
Example
To use the method CreateCopy()
, let's say you have a Customer
class and a Order
class, and you need to create copies (not references) but with new IDs. Then you can do the following:
Order CopyOrderWithNewPK(Order item)
{
Order newItem = item.CreateCopy(); // use ext. method to copy properties
newItem.OrderId = new Guid(); // create new primary key for the item
return newItem;
}
Not surprisingly, for the Customer class it would look the same:
Customer CopyCustomerWithNewPK(Customer item)
{
Customer newItem = item.CreateCopy(); // use ext. method to copy properties
newItem.CustomerId = new Guid(); // create new primary key for the item
return newItem;
}
Note that the values of all properties defined within the example classes are copied automatically. You can even clone an object of a 3rd party assembly if you don't own the source code. The trade-off is, that the reflection approach is slower.
2.) There's another another way to do it without reflection, inspired by this question. One advantage is that it even is able to clone the objects of the Entity Framework (for example to attach and re-attach entity objects to a different data context):
// using System.Runtime.Serialization;
public class Cloner<T>
{
readonly DataContractSerializer _serializer
= new DataContractSerializer(typeof(T));
/// <summary>
/// Clone an object graph
/// </summary>
/// <param name="graph"></param>
/// <returns></returns>
public T Clone(T graph)
{
MemoryStream stream = new MemoryStream();
_serializer.WriteObject(stream, graph);
stream.Seek(0, SeekOrigin.Begin);
return (T)_serializer.ReadObject(stream);
}
}
In order to not break the examples above, you can change the extension method CreateCopy
as follows:
public static class Extension
{
public static T CreateCopy<T>(this T src)
where T: new()
{
return (new Cloner<T>()).Clone(src);
}
}
Note: Although Cloner
is using System.Runtime.Serialization
, the object being cloned does not need to be serializable. This can be an advantage, other solutions I have seen can only clone serializable objects.