Introduction
We usually need to copy all contents of an instance to another which have the same object type (or heritage object). I know four ways to do that, some of them are good and some are bad.
Using the Code
- Copy all properties of the object to another. This is not a bad way. It clones properties' value without creating a new instance. But if we have more than 200 properties in the object, you know what will happen to us.
class ObjectA
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
}
class Run : IRun
{
public void CopyFromSecondToFirst(ObjectA firstObj, ObjectA secondObj)
{
firstObj.Property1 = secondObj.Property1;
firstObj.Property2 = secondObj.Property2;
firstObj.Property3 = secondObj.Property3;
}
}
We could also encapsulate this way to a method of the Object A:
class ObjectA
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public virtual void CloneFrom(ObjectA obj)
{
this.Property1 = obj.Property1;
this.Property2 = obj.Property2;
this.Property3 = obj.Property3;
}
}
-
Copy all properties by using PropertyInfo
. This is a reflection way. It's a dynamic way, but it costs too much time to copy values.
class Run : IRun
{
public void CopyFromNewToOrigin(ObjectA originObj, ObjectA newObj)
{
PropertyInfo[] properties = typeof(ObjectA).GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
var value = properties.GetValue(newObj, null) as string;
originObj.SetValue(originObj, value, null);
}
}
}
- MemberwiseClone() creates a shallow copy by creating a new object, and then copying the non-static fields of the current object to the new object. This method has almost the same performance as the first one, it means ten times faster than the reflection method. But it creates a new instance instead of just copying values of properties.
class ObjectA : ICloneable
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public object Clone()
{
return (ObjectA)this.MemberwiseClone();
}
}
In multi-thread UI development, this way is often used. But because it's a shallow copy, if in the class ObjectA
has a reference type property, this property's reference is copied but the referred object is not, therefore the original object and its clone refer to the same object.
MemberwiseClone
is a shallow copy, we can create a deep copy based on this shallow copy method. Here is MSDN's example of creating a deep copy:
public class IdInfo
{
public int IdNumber;
public IdInfo(int IdNumber)
{
this.IdNumber = IdNumber;
}
}
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person) this.MemberwiseClone();
other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
return other;
}
}
There are also other ways to have a deep copy. Shallow copy and deep copy are both well explained in the MSDN page: Object.MemberwiseClone Method.
In 3's shallow copy, class implemented System.ICloeanable. But MSDN remarked that: The ICloneable
interface simply requires that your implementation of the Clone
method return a copy of the current object instance. It does not specify whether the cloning operation performs a deep copy, a shallow copy, or something in between. Nor does it require all property values of the original instance to be copied to the new instance. For example, the NumberFormatInfo.Clone
method performs a shallow copy of all properties except the NumberFormatInfo.IsReadOnly
property; it always sets this property value to false
in the cloned object. Because callers of Clone cannot depend on the method performing a predictable cloning operation, we recommend that ICloneable not be implemented in public APIs.
Points of Interest
Instead of my four ways of copying an object, there is also something like AutoMapper. Wish my tip helps you.
Please also give me some other suggestions about this subject. Thanks!