简体   繁体   English

如何使用反射和递归从嵌套对象获取属性?

[英]How to get properties from nested object using reflection and recursion?

I have a set of classes, whose properties have data annotations on them. 我有一组类,它们的属性上有数据注释。 Some of these class properties are of primitive types (and by primitive, I also mean types such as string, double, datetime etc), while others are properties of a custom type. 这些类属性中的一些是原始类型的(按原语,我也指的是字符串,双精度型,日期时间等类型),而其他则是自定义类型的属性。

I would like to be able to iterate through the properties of a class and the properties of the nested objects and pull out the attributes of each property. 我希望能够遍历一个类的属性和嵌套对象的属性,并提取每个属性的属性。 I've played around with reflection and my code works fine, if the class under consideration has only one property of a custom type. 如果所考虑的类仅具有一个自定义类型的属性,那么我会进行反射,并且我的代码可以正常工作。 However when a class has multiple properties of a custom type and each of those properties have other custom types, I am completely lost on how I'd keep track of the objects/properties that have already been visited. 但是,当一个类具有一个自定义类型的多个属性,而每个属性具有其他自定义类型时,我将完全迷失如何跟踪已被访问的对象/属性。

This is where I have got so far. 这是我到目前为止所到之处。 I have seen a lot of examples on the forum, but they all have a simple nested class, where there is a maximum of one custom type per class. 我在论坛上看到了很多示例,但是它们都有一个简单的嵌套类,每个类最多有一个自定义类型。 Below is a sample of what I am trying to get done: 以下是我要完成的工作的示例:

Public Class Claim
    <Required()>
    <StringLength(5)>
    Public Property ClaimNumber As String
    <Required()>
    Public Property Patient As Patient
    <Required()>
    Public Property Invoice As Invoice
End Class

Public Class Patient
    <Required()>
    <StringLength(5)>
    Public Property MedicareNumber As String
    <Required()>
    Public Property Name As String
    <Required()>
    Public Property Address As Address
End Class

Public Class Address
    Public Property Suburb As String
    Public Property City As String
End Class

Public Class Invoice
    <Required()>
    Public Property InvoiceNumber As String
    <Required()>
    Public Property Procedure As String
End Class




 Public Shared Function Validate(ByVal ObjectToValidate As Object) As List(Of String)
          Dim ErrorList As New List(Of String)
             If ObjectToValidate IsNot Nothing Then

               Dim Properties() As PropertyInfo = ObjectToValidate.GetType().GetProperties()
                 For Each ClassProperty As PropertyInfo In Properties
                   Select Case ClassProperty.PropertyType.FullName.Split(".")(0)
                      Case "System" 
                        Dim attributes() As ValidationAttribute = ClassProperty.GetCustomAttributes(GetType(ValidationAttribute), False)
                                For Each Attribute As ValidationAttribute In attributes
                                    If Not Attribute.IsValid(ClassProperty.GetValue(ObjectToValidate, Nothing)) Then
                                        ErrorList.Add("Attribute Error Message")
                                    End If
                                Next
                            Case Else
                                Validate(ClassProperty.GetValue(ObjectToValidate, Nothing))
        **** ‘At this point I need a mechanism to keep track of the parent of ClassProperty and also mark ClassProperty as visited, so that I am able to iterate through the other properties of the parent (ObjectToValidate), without revisiting ClassProperty again.**

                        End Select
                    Next
                End If
                Return Nothing
            End Function

The most straightforward (and probably easiest) way to approach this is to keep a Dictionary of class property attributes keyed by class name. 解决此问题的最直接(可能是最简单)的方法是保留由类名称作为键的类属性属性字典。

If I were approaching this, I would probably create a class to hold the property attributes: 如果要实现这一点,我可能会创建一个类来保存属性属性:

Public Class PropertyAttribute
   Public PropertyName As String
   Public PropertyTypeName As String
   Public Required As Boolean
   Public StringLength As Integer
End Class

Then create a class to hold information about each class' properties: 然后创建一个类,以保存有关每个类的属性的信息:

Public Class ClassAttributes
   Public ClassName As String
   ' You could also use a dictionary here to key properties by name
   Public PropertyAttributes As New List(Of PropertyAttribute)
End Class

Finally, create a dictionary of ClassAttributes to keep track of which custom classes you have already processed: 最后,创建一个ClassAttributes字典来跟踪您已经处理过的自定义类:

Public ProcessedClasses As New Dictonary(Of String, ClassAttributes)

The key for the dictionary is the classname. 字典的键是类名。

When you are processing the attributes through reflection, if the property type is custom, check the dictionary for the existence of the class. 通过反射处理属性时,如果属性类型是自定义的,请检查字典中是否存在该类。 If it is there, you don't have to process it. 如果存在,则无需处理。

If it is not there, add a new instance to the dictionary immediately (so that nested objects of the same type are safely handled) and then process the attributes of the class. 如果不存在,请立即将新实例添加到字典中(以便安全地处理相同类型的嵌套对象),然后处理该类的属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM