How to copy object properties to another instance of the same class in C#
March 3, 2010
Copy constructor does exist in C++, but not in C#. There is a great artilce by John Conners dedicated to this issue. It helped me to solve my issue, when i was working on implemention of IEditableObject interface in my ViewModel. Here is the issue. Interface IEditableObject suppose that you will create internal copy of object’s data, while it being edited. If edit operation was canceled, you should restore state of you object. Quite simple. ViewModel always implements INotifyPropertyChanged to notify View about changes. In order to restore View’s state you need to refresh ViewModel properties, not replace internal object. This leads to ugly code, like this:
public override void CancelEdit()
{
if (IsEditing)
{
Name = InternalCopy.Name;
Address= InternalCopy.Address;
SSN= InternalCopy.SSN;
//and so on...
IsEditing = false;
}
}
Public Overloads Overrides Sub CancelEdit()
If IsEditing Then
Name = InternalCopy.Name
Address = InternalCopy.Address
SSN = InternalCopy.SSN
'and so on...
IsEditing = False
End If
End Sub
You can end up with a bunch of properties being copied, but that is not the worst. New properties will not be copied automatically, so you will have tricky bugs in your app. Definitely a solution is needed. It is pretty obvious. I have created class with extension method, which copies all properties using reflection from one instance to another. It perfectly addresses the issue.
public static class ObjectCopier
{
public static void CopyFields<T>(this T dest, T source)
{
PropertyInfo[] properties = dest.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in properties)
{
propertyInfo.SetValue(dest, propertyInfo.GetValue(source, null), null);
}
}
}
Public Module ObjectCopier
<System.Runtime.CompilerServices.Extension()> _
Public Sub CopyFields(Of T)(ByVal dest As T, ByVal source As T)
Dim properties As PropertyInfo() = dest.[GetType]().GetProperties(BindingFlags.[Public] Or BindingFlags.Instance)
For Each propertyInfo As PropertyInfo In properties
propertyInfo.SetValue(dest, propertyInfo.GetValue(source, Nothing), Nothing)
Next
End Sub
End Module
Look, how clear and cool it became.
public override void CancelEdit()
{
if (IsEditing)
{
this.CopyFields(InternalCopy);
IsEditing = false;
}
}
Public Overloads Overrides Sub CancelEdit()
If IsEditing Then
Me.CopyFields(InternalCopy)
IsEditing = False
End If
End Sub
Useful, thank you!