【问题标题】:Reflection - Iterating Class with properties that are classes反射 - 具有类属性的迭代类
【发布时间】:2014-10-20 23:12:03
【问题描述】:

我需要遍历一个类的整个结构。我正在询问发送到我的 WCF 方法中的对象,并且我目前在每个列出所有属性及其值的类中都有一个 ToString() 重载。这行得通;但是是硬编码的,每次我们向类添加属性时都需要更新。

当前的解决方案是 VB,但下一个版本将是 C# - 因此两个标签。

该类可以仅由原始类型组成,也可以由其他对象组成。遍历一个简单的类不是问题。

我无法确定某个属性何时实际上是另一个类。因此,鉴于下面的示例,我可以遍历 Appointment 和 Patient 并转储它们每个属性的值。

我一直在尝试遍历 PatientAppointment。我搜索了 MSDN 和 SO,尝试了该类型中的无数属性等,但均无济于事。

Public Class PatientAppointment
    Public Property Pat As Patient
    Public Property Appt As Appointment
End Class

Public Class Appointment
    Public Property ApptProp1 As String
    Public Property ApptProp2 As Integer
End Class

Public Class Patient
    Public Property PatProp1 As String
    Public Property PatProp2 As Integer
End Class

【问题讨论】:

  • 你遇到了什么错误?
  • 您究竟想如何迭代PatientAppointment?是否要递归迭代(迭代PatientAppointment 的每个属性以及PatAppt 的每个属性)?或者您只是想知道该属性是否是一个类?
  • - 我没有收到错误消息。
  • 你想做什么反射是必要的?
  • @DonnyMcCoy 有一些过滤方法:stackoverflow.com/questions/2442534/…

标签: vb.net


【解决方案1】:

听起来您可能正在寻找一种在一定程度上确定您的类型的方法。一种方法可能是使用自定义属性,该属性使用反射很容易找到和过滤。

Public Class RealMcCoy
    Inherits Attribute

    Public Property IsReal As Boolean 

    Public Sub New(b as Boolean)
      IsReal = b
    End Sub
End Class

<RealMcCoy(True)>      
Public Class Patient
    ...
End Class

<RealMcCoy(True)>   
Public Class Appointment
   ...
End Class

现在在迭代属性时,检查它是否是 RealMcCoy 以查看它是否是您想要/需要钻取的。由于 Attribute 将在 Type 上,因此有一个额外的步骤来获取每个属性的 Type 并轮询 that

    Dim props As PropertyInfo() = myFoo.GetType.GetProperties
    Dim pt As Type

    For Each pi As PropertyInfo In props
        pt = pi.PropertyType         ' get the property type

        Dim attr() As RealMcCoy =
                DirectCast(pt.GetCustomAttributes(GetType(RealMcCoy), True), RealMcCoy())
        If attr.Length > 0 Then
            ' bingo, baby...optional extra test:
            If attr(0).IsReal Then
                Console.Beep()
            End If
        Else
            ' skip this prop - its not a real mccoy
        End If
    Next
End Sub

如果您添加一个类型而不添加属性,它会中断,但它比必须更新每个类型的组成属性更容易中断。伪造的接口会更容易查询,但也有同样的缺点。

我不确定我是否理解“游戏”事物的问题 - 你是否害怕其他类型会被选中?属性将很难“游戏”,因为它们被编译到程序集中,但以上内容仍可用于返回 GUID(可能附加到程序集?)而不是 bool 以提供一些保证。

很难获得绝对的确定性。


RealMcCoy 属性可能不会应用于您的顶级类型 (PatientAppointment),而只会应用于将用作其他类型的属性的类型(类)。对象是一种轻松识别这些的方法。

根据其使用方式,已经标识为 RealMcCoys 的 TypeName-PropertyName 对的字典或哈希表可能很有用,因此可以缩短整个反射过程。而不是即时添加,您可能可以将整个列表预先构建为shown in this answer - 请参阅RangeManager.BuildPropMap 过程。

我不太确定继承方法,因为您可能希望在某处实际使用继承。接口可能会更好地工作:最初,它的存在可能是一开始的触发器,但也可以用来提供服务。


简单的测试用例:

' B and C classes are not tagged
Friend Class FooBar
    Public Property Prop1 As PropA
    Public Property Prop2 As PropB
    Public Property Prop3 As PropC
    Public Property Prop4 As PropD
    Public Property Prop5 As PropE
End Class

在 for 循环中添加一行:

Dim f As New FooBar
' use instance:
Dim props As PropertyInfo() = f.GetType.GetProperties
Dim pt As Type

For Each pi As PropertyInfo In props
    pt = pi.PropertyType

    Dim attr() As RealMcCoy =
            DirectCast(pt.GetCustomAttributes(GetType(RealMcCoy), True), RealMcCoy())

    Console.WriteLine("Prop Name: {0},  prop type: {1}, IsRealMcCoy? {2}",
            pi.Name, pt.Name, If(attr.Length > 0, "YES!", "no"))
Next

输出:

Prop Name: Prop1  prop type: PropA IsRealMcCoy? YES!  
Prop Name: Prop2  prop type: PropB IsRealMcCoy? no  
Prop Name: Prop3  prop type: PropC IsRealMcCoy? no 
Prop Name: Prop4  prop type: PropD IsRealMcCoy? YES! 
Prop Name: Prop5  prop type: PropE IsRealMcCoy? YES!

【讨论】:

  • 另一种方法是让每个使用的类都继承自 McCoy 基类,并简单地检查类型 IsAssignableFrom 是否作为信号
  • 嗨 Plutonix,我现在正在玩这个。我也喜欢 IsAssignableFrom 的想法,并且可能会在 C# 版本中使用它,因为我计划从该版本中的多个类继承。所以无论如何,我对你的样本有疑问。在你说 dim attr() as mccoy 的地方,mccoy 到底应该是什么?我尝试了 realmccoy,但我得到了 attr() 的空列表。
  • 我进行了编辑 - 应该是 RealMcCoy - 我试图避免 RealMcCoy.IsRealMcCoy 并删除了一些字符。很明显会有很多属性没有有属性的类型,但是那些有属性的应该会出现。这是工作/测试代码(现在)。
  • 鉴于属性位于用作属性的 Type 上,我在答案中添加了一个额外的步骤(注意 pt 获取attr())。抱歉,我最初是直接在属性上使用它进行测试的(就像在那个 RangeAttribute 中一样)。
  • Plutonix,非常感谢您的帮助。我现在正在研究 GetValue 部分,因为该方法根据属性或属性的属性(递归)而有所不同。对于延迟标记您的答案,我深表歉意——不过是周五下午的会议。您可能对将属性信息对象转换为其真实对象有任何指导吗?编辑添加我在直接演员表中遗漏了一些东西,所以我不断收到可怕的对象不匹配异常。
【解决方案2】:

非常感谢 Plutonix! 这是我的最终功能。如果我的回答取代了 Plutonix 的回答,那么我需要调整这一点,因为他让我走到了这一步,这完全值得称赞。

我已经对它进行了 8 级嵌套类型的测试。由于这只是一个原型,所以进行了初步的异常处理。

    Function IterateClass(ByVal o As Object, ByVal topLevelFlag As Boolean, ByVal indentLevel As Integer) As String

    Dim retVal As New StringBuilder

    Try

        '' Iterate top level of supplied type ''
        '' Query each property for custom attribute ADMICompositeClassAttribute ''
        '' If exists and set to true then we're dealing with a base class that we need to break down recursively ''
        '' If not then immediately dump this type's properties ''


        '' Build header of output ''
        If topLevelFlag Then

            '' <<EXCERPTED>> ''

        End If


        '' We start walking through the hierarchy here, no matter how much we recurse we still need to do this each time ''
        Dim properties_info As PropertyInfo()
        properties_info = o.GetType().GetProperties()

        For Each p As PropertyInfo In properties_info
            Dim propName As String = p.Name
            Dim propTypeList As List(Of String) = p.PropertyType.ToString().Split(".").ToList()
            Dim propType As String = propTypeList(propTypeList.Count - 1).Replace("[", "").Replace("]", "")
            Dim pValue As Object = Nothing

            '' We check this type for custom attribute ADMICompositeClassAttribute ''
            '' Is this type a composite? ''
            Dim oAttr() As ADMICompositeClassAttribute = p.PropertyType.GetCustomAttributes(GetType(ADMICompositeClassAttribute), False)
            Dim indentString As String = String.Concat(Enumerable.Repeat(" ", indentLevel))
            If oAttr.Length > 0 AndAlso oAttr(0).IsComposite Then

                '' This is a nested type, recurse it ''
                Dim dynType As Type = p.PropertyType()
                Dim dynObj As Object = Activator.CreateInstance(dynType)

                '' <<EXCERPTED ''

            Else

                pValue = p.GetValue(o, Nothing)

            End If

        Next


    Catch ex As Exception
        retVal.AppendLine(ex.ToString())

    End Try
    Return retVal.ToString()


End Function

【讨论】:

    猜你喜欢
    • 2018-12-31
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 2014-05-24
    • 1970-01-01
    • 2017-04-04
    相关资源
    最近更新 更多