I've actually done something similar using reflection, to help with modelbinding in an MVC project. I've defined a custom attribute "Updatable", and a generic extension method. This is a bit safer, as I have to explicitly mark attributes to be cloned with my custom attribute (or via a metadata class) for the behaviour to do anything, but I'm sure you could adapt it for your own purposes.
Here's my custom attribute (not very exciting!)
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False)>
Public Class UpdateableAttribute : Inherits Attribute
End Class
And here's the extension method
<Extension()>
Public Sub UpdateObject(Of T)(ByVal targetObject As T, ByVal otherObject As T)
Dim metaDataType As MetadataTypeAttribute = GetType(T).GetCustomAttributes(GetType(MetadataTypeAttribute), True).FirstOrDefault
If metaDataType Is Nothing Then
For Each prop As Reflection.PropertyInfo In GetType(T).GetProperties()
If prop.GetCustomAttributes(GetType(UpdateableAttribute), True).Count > 0 Then
Dim targetValue = prop.GetValue(targetObject, {})
Dim otherValue = prop.GetValue(otherObject, {})
If Not targetValue = otherValue Then
prop.SetValue(targetObject, otherValue, {})
End If
End If
Next
Else
Dim targetProps As Reflection.PropertyInfo() = GetType(T).GetProperties()
For Each prop As Reflection.PropertyInfo In metaDataType.MetadataClassType.GetProperties()
If prop.GetCustomAttributes(GetType(UpdateableAttribute), True).Count > 0 Then
Dim propName As String = prop.Name
Dim targetProperty = targetProps.Single(Function(p) p.Name = propName)
Dim targetValue = targetProperty.GetValue(targetObject, {})
Dim otherValue = targetProperty.GetValue(otherObject, {})
If Not targetValue = otherValue Then
targetProperty.SetValue(targetObject, otherValue, {})
End If
End If
Next
End If
End Sub
Behaves nicely for me, it obviously uses reflection so isn't lightning quick but saves me a heck of a lot of left = right coding.
If you have access to the target class, you can just do this, in this example only firstname and surname will clone.
Public Class Person
<Updateable()>
Public Property FirstName As String
<Updateable()>
Public Property Surname As String
Public Property ShoeSize As Integer
Public Property Gender As Gender
Public Property BirthDate As DateTime
Public Property FavoriteCarMake
End Class
And an example using a metadata class to do the same thing, which is good for if you can't edit the target class directly (e.g. Entity Framework classes if you don't fancy editing T4 templates)
<MetadataType(GetType(PersonMetadata))>
Public Class Person
Public Property FirstName As String
Public Property Surname As String
Public Property ShoeSize As Integer
Public Property Gender As Gender
Public Property BirthDate As DateTime
Public Property FavoriteCarMake
End Class
Public Class PersonMetadata
<Updateable()>
Public Property FirstName
<Updateable()>
Public Property Surname
End Class
In both cases you can simply do something like this:
Dim person1 As New Person With ...
Dim person2 As New Person With ...
person1.UpdateObject(person2)