Search code examples
vb.netsystem.reflection

List all property names in classes and sub classes - problem including ilist 'Object does not match target type.'


I want to get all property names in a class and list(of class) in deep hierarchy.

I can get property names of Address and Address.Floors but with Address.Floors.Peoples I get an error that the object does not match target type.

Here is a simple example of a simple class

Public Class ClsContainer
    Class Address
        Public Property StreetName As String = ""
        Public Property CipCity As String = ""
        Public Property Floors As New List(Of Floor)
    End Class
    Class Floor
        Public Property Name As String = ""
        Public Property Peoples As New List(Of People)
    End Class
    Class People
        Public Property Name As String = ""
    End Class
End Class

and here is the windows form for test

Public Class Form1
    Dim MyData As New ClsContainer.Address
    Dim Result As String = ""
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Result = ""
        GetProperties(MyData, MyData.GetType, 0)
        MsgBox(Result)
    End Sub

    Private Sub GetProperties(Obj As Object, ObjType As Type, Indent As Integer)
        Dim Pre = Strings.StrDup(Indent, " ")
        For Each P As PropertyInfo In ObjType.GetProperties
            If P.PropertyType.IsEnum Then
                Result &= Pre & P.Name & " (Enum: " & P.PropertyType.Name & ") ->"
                Dim EnumUnderlyingType = System.Enum.GetUnderlyingType(P.PropertyType)
                Dim EnumValues = System.Enum.GetValues(P.PropertyType)
                For Each V In EnumValues
                    Result &= Pre & " [" & V & "=" & V.ToString & "]"
                Next
                Result &= vbCrLf
            ElseIf GetType(IList).IsAssignableFrom(P.PropertyType) AndAlso P.PropertyType.IsGenericType Then
                Result &= Pre & "[" & P.Name & "] Generic " & P.PropertyType.Name & vbCrLf

                ' here it fails with Address.Floors.Peoples
                Dim Item As IList = DirectCast(P.GetValue(Obj, Nothing), IList)
                Dim P1 As PropertyInfo = Item.GetType.GetProperty("Item")
                If P1 IsNot Nothing Then
                    If P1.PropertyType.IsClass And P1.PropertyType.FullName.StartsWith("System") = False Then
                        Indent += 4
                        GetProperties(Obj, P1.PropertyType, Indent)
                        Indent -= 4
                    End If
                End If
            Else
                If P.PropertyType.IsClass And P.PropertyType.FullName.StartsWith("System") = False Then
                    Indent += 4
                    GetProperties(Obj, P.PropertyType, Indent)
                    Indent -= 4
                Else
                    Result &= Pre & P.Name & " " & P.PropertyType.Name & vbCrLf
                End If
            End If
        Next
    End Sub
End Class

Solution

  • You don't have to create an instance of a class to read its internal structure.

    You can use GetGenericArguments() method:

    ' here it fails with Address.Floors.Peoples
    'Dim Item As IList = DirectCast(P.GetValue(Obj, Nothing), IList)
    'Dim P1 As PropertyInfo = Item.GetType.GetProperty("Item")
    Dim P1Type = P.PropertyType.GetGenericArguments().Single()
    'If P1 IsNot Nothing Then
    If P1Type.IsClass And P1Type.FullName.StartsWith("System") = False Then
            Indent += 4
            GetProperties(Obj, P1Type, Indent)
            Indent -= 4
        End If
    'End If
    

    Result:

    enter image description here