Home > Net >  Property Copying Between Two Objects using Reflection Recursive
Property Copying Between Two Objects using Reflection Recursive

Time:05-07

I am trying to do a deep copy a source object's property values to the destination object's property of the same name. The problem I have run into is is that if the source property is a collection, List(of integer) in this case. It will copy it as a reference and not an independent copy which is expected and can be seen in the output results. I plan to recursively call the Copy function for each property that is a collection to do a deep copy on that object. L'ii also add some associate code.

The problem I am having is I can't detect a List(of) object when doing a type comparison 2) Although this works when doing a Int16 type comparison 1) I can get it to work when I compare the type.Name 3)

Is this 3) robust enough or is there a way to make 2) work?

Output:
Unchanged
Source.ID:1 Dest.ID:1
Source.Description:Source Description   Dest.Description:Source Description
Source.Links(0):10  Dest.Links(0):10
Source.Links(1):11  Dest.Links(1):11
changed
Source.ID:1 Dest.ID:100
Source.Description:Source Description   Dest.Description:Dest Description
Source.Links(0):50  Dest.Links(0):50
Source.Links(1):11  Dest.Links(1):11
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Dim Source As New DataClass
        Dim SourceLinks As New List(Of Integer)({10, 11, 12})
        Source.ID = 1
        Source.Description = "Source Description"
        Source.Links = SourceLinks

        Dim Dest As New DataClass
        PropertyCopier(Of DataClass, DataClass).Copy(Source, Dest)

        Debug.Print("Unchanged")
        Debug.Print("Source.ID:" & Source.ID & vbTab & "Dest.ID:" & Dest.ID)
        Debug.Print("Source.Description:" & Source.Description & vbTab & "Dest.Description:" & Dest.Description)
        Debug.Print("Source.Links(0):" & Source.Links(0) & vbTab & "Dest.Links(0):" & Dest.Links(0))
        Debug.Print("Source.Links(1):" & Source.Links(1) & vbTab & "Dest.Links(1):" & Dest.Links(1))

        Debug.Print("changed")
        Dest.ID = 100
        Dest.Description = "Dest Description"
        Dest.Links(0) = 50
        Debug.Print("Source.ID:" & Source.ID & vbTab & "Dest.ID:" & Dest.ID)
        Debug.Print("Source.Description:" & Source.Description & vbTab & "Dest.Description:" & Dest.Description)
        Debug.Print("Source.Links(0):" & Source.Links(0) & vbTab & "Dest.Links(0):" & Dest.Links(0))
        Debug.Print("Source.Links(1):" & Source.Links(1) & vbTab & "Dest.Links(1):" & Dest.Links(1))
    End Sub
End Class
Public Class DataClass
    Public Property ID As Int16
    Public Property Description As String
    Public Property Links As List(Of Integer)
End Class
Public Class PropertyCopier(Of TSource As Class, TDestination As Class)
    Public Shared Sub Copy(ByVal Source As TSource, ByVal Destination As TDestination)
        Dim SourceProperties = Source.[GetType]().GetProperties()
        Dim DestinationProperties = Destination.[GetType]().GetProperties()

        For Each SourceProperty In SourceProperties
            For Each DestinationProperty In DestinationProperties
                If SourceProperty.Name = DestinationProperty.Name AndAlso SourceProperty.PropertyType = DestinationProperty.PropertyType Then
                    If SourceProperty.PropertyType = GetType(Int16) Then
                        '1) Correctly detects the property type as a integer
                    ElseIf SourceProperty.PropertyType = GetType(List(Of)) Then
                        '2) Does not detect the List(of ) type
                    ElseIf SourceProperty.PropertyType.Name = GetType(List(Of)).Name Then
                        '3) Correctly detects the property type as List(of )
                    End If
                    If SourceProperty.CanWrite Then DestinationProperty.SetValue(Destination, SourceProperty.GetValue(Source))
                    Exit For
                End If
            Next
        Next
    End Sub
End Class

CodePudding user response:

The problem is that the generic type parameter of your object is set to something specific, e.g. you're comparing List(Of String) to List(Of) and they are not the same. What you need to do is get the generic type definition from that generic type, i.e.

ElseIf SourceProperty.PropertyType.IsGenericType AndAlso
       SourceProperty.PropertyType.GetGenericTypeDefinition() Is GetType(List(Of)) Then

Notice the correct us of Is rather than = as well.

CodePudding user response:

Depending on what you need to work with, you may also want to look for interface compatibility rather than exact equality. You can do that using Type.IsAssignableFrom. I have similar code that looks for a list like this:

If sourceProperty.PropertyType.IsGenericType _
   AndAlso GetType(IList).IsAssignableFrom(sourceProperty.PropertyType) Then
    '...
End If

(building upon the previous answer)

If you need it, you can get the generic type argument using e.g. sourceProperty.PropertyType.GenericTypeArguments(0).

  • Related