使用Lambda表达式遍历类属性

4

假设我有以下几个类:

Public Class Vehicle
        Sub New()
            Car = New Car()
            VehicleName = String.Empty
        End Sub

        Public Property Car As Car

        <Mask()>
        Public Property VehicleName As String
    End Class

    Public Class MaskAttribute
        Inherits Attribute

        Public Property Masking As String
    End Class

    <Serializable()>
     Public Class Car
        Sub New()
            CarName = String.Empty
        End Sub

        <Mask()>
        Public Property CarName As String
    End Class

在上述示例代码中,有一个名为Mask的自定义属性。
假设有一个对象Dim v As new Vehicle() 如何获取该对象所有具有Mask自定义属性的属性?
因此,在这种情况下,预期的循环属性是CarName和VehicleName,因为它们都有掩码属性。
我知道使用反射性能会比使用lambda表达式慢。如果我错了,请纠正我。
有没有用lambda表达式实现该目标的想法?
谢谢!

4
我不知道你如何使用Lambda表达式,在不使用反射的情况下完成这个任务。这两者是完全不同的东西,Lambda表达式(或表达式树)不能替代反射。 - MarcinJuraszek
使用GetCustomAttributes(function(m) m)方法,将返回具有Mask自定义属性的属性。 - Hatjhie
4
但是您仍然需要使用反射来使用自定义属性获取这些属性。 - MarcinJuraszek
1
你应该先从不使用反射或表达式树编写的实现开始。只是硬编码属性列表。然后,你可以尝试动态获取属性并使用表达式树生成代码。最好知道如果没有表达式,你要生成的代码会是什么样子,就算你自己编写它。 - MarcinJuraszek
1
@Hatjhie,Marcin提供了一些关于如何实现你需要的功能的好建议。最好尝试按照Marcin的建议去做,然后当你遇到问题时,再发布这些特定的问题。这似乎对于一个单一的问题来说太宽泛了。建议是:使用反射仅获取在给定类型中调用你的逻辑的第一个必要数据,生成正确的表达式树并将其编译为Lambda表达式。每次对于相同类型的下一次调用都会获得与你在前面编写和编译的标准.NET代码相当的性能。 - SeraM
显示剩余6条评论
1个回答

0
使用以下代码获取带有v对象(您在示例中使用的名称)的Mask属性的所有属性描述符列表:
    Dim props As List(Of PropertyDescriptor) = (
                From C As PropertyDescriptor In TypeDescriptor.GetProperties(v.GetType)
                Where C.Attributes.OfType(Of MaskAttribute)().Count > 0
                Select C
    ).ToList

你需要导入 System.ComponentModel


获取属性值

如果您需要获取属性的值,可以使用以下代码(在vb.net中使用属性名称访问属性):

Public Function GetPropertyValue(ByVal obj As Object, ByVal PropName As String) As Object
    Dim objType As Type = obj.GetType()
    Dim pInfo As System.Reflection.PropertyInfo = objType.GetProperty(PropName)
    Dim PropValue As Object = pInfo.GetValue(obj, Reflection.BindingFlags.GetProperty, Nothing, Nothing, Nothing)
    Return PropValue
End Function

请注意,在我们的示例中,属性的名称由列表props中每个 PropertyDescriptor 的属性Name给出。

更新

在您的示例中,这种方法不起作用,因为您在车辆类型的其他对象内部有一个汽车类型的对象,而我没有考虑内部对象。

我发现解决此问题的方法是使用递归:

Sub GetPropertiesWithMaskAttribute(Obj As Object, ByRef props As List(Of PropertyDescriptor))
    Dim props1 As List(Of PropertyDescriptor) = (From C As PropertyDescriptor In TypeDescriptor.GetProperties(Obj) Select C).ToList
    For Each prop In props1
        If prop.Attributes.OfType(Of MaskAttribute)().Count > 0 Then
            props.Add(prop)
        Else
            If prop.ComponentType.IsClass Then
                GetPropertiesWithMaskAttribute(GetPropertyValue(Obj, prop.Name), props)
            End If
        End If
    Next
End Sub

像这样调用:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim props As New List(Of PropertyDescriptor)
    GetPropertiesWithMaskAttribute(v, props)
End Sub

然后,props 列表将包含所有带有 MaskAtribute 属性的属性。请注意,我使用了之前声明的子 GetPropertyValue


嗨,谢谢你的回答。我想使用表达式来解决这个问题,而不是反射。你有什么建议吗?谢谢。 - Hatjhie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接