Copying class properties using .NET Reflection
7 Comments Published by Erik Burger June 6th, 2008 in ProgrammingI ran into a situation a while ago that I needed to retrieve a serialized object from the database, copy its properties to another object and send that object over the wire. Why the copying? The object stored in the database were written in .NET 2.0, whereas the service I was sending the object to expected .NET 3.5 (WCF) objects.
It was also perfectly possible that the .NET 3.5 objects, which were being developed by another team, would have had properties added or removed without notification.
The following code allows you to copy property values from one object into another. If a property does not exist in the target object, it is ignored. I ran into some issues with indexed properties (aka lists and arrays) which do not allow you to copy the properties of their contained items. So I do some additional reflection magic there to build the array or list dynamically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | Private Function CopyProperties(Of sourceType As {Class, New}, targetType As {Class, New})(ByVal source As sourceType, ByVal target As targetType) As targetType Dim retValue As New targetType Dim sourceProperties() As PropertyInfo = source.GetType().GetProperties() Dim targetProperties() As PropertyInfo = GetType(targetType).GetProperties() For Each sourceProp As PropertyInfo In sourceProperties For Each targetProp As PropertyInfo In targetProperties If sourceProp.Name <> targetProp.Name Then Continue For ' Only try to set property when able to read the source and write the target If sourceProp.CanRead And _ targetProp.CanWrite Then ' We want to leave System types alone If sourceProp.PropertyType.IsClass And _ Not sourceProp.PropertyType.FullName.StartsWith("System.") Then Dim sT As Type = Type.GetType(sourceProp.PropertyType.AssemblyQualifiedName) Dim tT As Type = Type.GetType(targetProp.PropertyType.AssemblyQualifiedName) Dim params(0 To 1) As Object ' If property is an array or a list, we need to treat it different If sourceProp.GetIndexParameters().Length = 0 Then params(0) = sourceProp.GetValue(source, Nothing) params(1) = targetProp.GetValue(target, Nothing) targetProp.SetValue(retValue, _ GenericCopyProperties(sT, tT).Invoke(Me, params), _ Nothing) Else Dim count As Integer = GetType(sourceType).InvokeMember("Count", BindingFlags.GetProperty, Nothing, source, Nothing) For i As Integer = 0 To (count - 1) Dim obj As Object() = New Object() {i} params(0) = sourceProp.GetValue(source, obj) If target IsNot Nothing Then params(1) = targetProp.GetValue(target, obj) End If retValue.GetType().InvokeMember("Add", BindingFlags.InvokeMethod, Nothing, _ retValue, New Object() {GenericCopyProperties(sT, tT).Invoke(Me, params)}) Next End If Else targetProp.SetValue(retValue, sourceProp.GetValue(source, Nothing), Nothing) End If End If Exit For Next Next Return retValue End Function |
The function above is a generic function as I needed to call some methods on the Type of the objects. I wrapped the dynamic creation of the generic method in the following function.
1 2 3 | Private Function GenericCopyProperties(ByVal sourceType As Type, ByVal targetType As Type) As MethodInfo Return Me.GetType().GetMethod("CopyProperties").MakeGenericMethod(sourceType, targetType) End Function |
Lastly, the snippet below shows how to call the function.
1 2 3 4 5 | Dim params(0 To 1) As Object params(0) = sourceObject params(1) = targetObject targetObject = GenericCopyProperties(sourceObject.GetType(), targetObject.GetType()).Invoke(Me, params) |
Personally, I love the mix of different techniques here. Reflection, dynamic methods, recursion and generics are very powerful on their own, but combined there’s some real magic waiting to be discovered


Erik, good code you could speed up the code if cache the generic methods.
Hi Joey,
That would definately be the first thing I’d do if performance would become an issue.
Erik
Does this do a deep or shallow copy?
I am trying to copy a LINQ Entity class and am getting an error in the GenericCopyProperties function. The MakeGenericMethod’s sourceType parameter is null when it hits that line of code (though it is populated beforehand). Any help would be greatly appreciated.
Hi Jimi,
This *should* do a deep copy.
As for the error copying your LINQ Entity class, if you could send me the code you are working on I’ll be more than happy to take a look. My email address is eburger at antares dot nl.
Cheers,
Erik
Hi Jimi,
Great coding !!
Do you have it in C#, can you send it to me? I’m a little bit lazy today
Thanks
PC
Hi Paulo,
You just reminded me to update my post to include the C# code..the project I worked on while I created this was in VB. In the meanwhile, check out this link and see how far you get
http://www.developerfusion.com/tools/convert/vb-to-csharp/
Erik