属性 使用反射递归在两个对象之间复制
Property Copying Between Two Objects using Reflection Recursive
我正在尝试将源对象的 属性 值深度复制到目标对象的同名 属性。
我遇到 运行 的问题是,如果源 属性 是一个集合,在这种情况下是 List(of integer)。它将复制它作为参考,而不是预期的独立副本,并且可以在输出结果中看到。
我计划为每个集合 属性 递归调用 Copy 函数,以便对该对象进行深层复制。 L'ii 还添加了一些关联代码。
我遇到的问题是在进行类型比较时无法检测到 List(of) 对象 2)
尽管这在进行 Int16 类型比较时有效 1)
当我比较 type.Name 3)
时,我可以让它工作
这 3) 是否足够强大,或者是否有办法使 2) 工作?
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
问题是您的对象的泛型类型参数被设置为特定的东西,例如您将 List(Of String)
与 List(Of)
进行比较,但它们并不相同。您需要做的是从该泛型类型中获取泛型类型定义,即
ElseIf SourceProperty.PropertyType.IsGenericType AndAlso
SourceProperty.PropertyType.GetGenericTypeDefinition() Is GetType(List(Of)) Then
注意 Is
的正确用法,而不是 =
。
根据您需要使用的内容,您可能还希望寻找接口兼容性而不是完全相等。您可以使用 Type.IsAssignableFrom
来做到这一点。我有类似的代码来查找这样的列表:
If sourceProperty.PropertyType.IsGenericType _
AndAlso GetType(IList).IsAssignableFrom(sourceProperty.PropertyType) Then
'...
End If
(基于之前的回答)
如果需要,您可以使用例如sourceProperty.PropertyType.GenericTypeArguments(0)
.
我正在尝试将源对象的 属性 值深度复制到目标对象的同名 属性。 我遇到 运行 的问题是,如果源 属性 是一个集合,在这种情况下是 List(of integer)。它将复制它作为参考,而不是预期的独立副本,并且可以在输出结果中看到。 我计划为每个集合 属性 递归调用 Copy 函数,以便对该对象进行深层复制。 L'ii 还添加了一些关联代码。
我遇到的问题是在进行类型比较时无法检测到 List(of) 对象 2) 尽管这在进行 Int16 类型比较时有效 1) 当我比较 type.Name 3)
时,我可以让它工作这 3) 是否足够强大,或者是否有办法使 2) 工作?
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
问题是您的对象的泛型类型参数被设置为特定的东西,例如您将 List(Of String)
与 List(Of)
进行比较,但它们并不相同。您需要做的是从该泛型类型中获取泛型类型定义,即
ElseIf SourceProperty.PropertyType.IsGenericType AndAlso
SourceProperty.PropertyType.GetGenericTypeDefinition() Is GetType(List(Of)) Then
注意 Is
的正确用法,而不是 =
。
根据您需要使用的内容,您可能还希望寻找接口兼容性而不是完全相等。您可以使用 Type.IsAssignableFrom
来做到这一点。我有类似的代码来查找这样的列表:
If sourceProperty.PropertyType.IsGenericType _
AndAlso GetType(IList).IsAssignableFrom(sourceProperty.PropertyType) Then
'...
End If
(基于之前的回答)
如果需要,您可以使用例如sourceProperty.PropertyType.GenericTypeArguments(0)
.