获取通过lambda表达式传递的嵌套属性的值

时间:2014-11-17 18:51:54

标签: .net vb.net reflection lambda propertyinfo

我正在尝试为一个类构建一个字符串,该类包含该属性的所有属性名称及其各自值的列表。

根据问题Get Property Info from an object without giving the property name as string,我使用Expression Func类型T, Object来获取属性名称,如下所示:

Private Function GetPropertyValuePair(Of T)(lambda As Expression(Of Func(Of T, Object))) As String
    Dim body As Expression = lambda

    'ensure we have the right type of thing
    If TypeOf body Is LambdaExpression Then body = DirectCast(body, LambdaExpression).Body
    If TypeOf body Is UnaryExpression Then body = DirectCast(body, UnaryExpression).Operand
    If body.NodeType <> ExpressionType.MemberAccess Then Throw New InvalidOperationException()

    'get property info
    Dim memberInfo = DirectCast(body, MemberExpression).Member
    Dim propInfo = DirectCast(memberInfo, PropertyInfo)

    Return propInfo.Name + " - " + propInfo.GetValue(Me, Nothing)
End Function

通过这种方式,我通过PropertyInfo获取当前值,并使用GetValue在当前实例中搜索该属性。

然后我可以这样称呼它:

GetPropertyValuePair(Of Foo)(Function(x) x.Bar)

将产生:

Bar - WhateverTheValueIsForBar

问题就是当我有嵌套属性时,GetValue会抛出异常:

  

对象与目标类型不匹配。

例如,在运行以下表达式时:

GetPropertyValuePair(Of Foo)(Function(x) x.Bar.Car)

属性信息的类型为Car,但不能直接在Foo找到。

我是否可以从原始lambda表达式中获取实例值,而无需首先使用GetValue进行搜索?

这可以使用MVC @Html.EditorFor帮助器,因此必须有一些机制来传递传入函数的值,如下所示:

@Html.EditorFor(Function(model) model.Bar.Car)

任何想法?

1 个答案:

答案 0 :(得分:1)

我根据How to evaluate a lambda expression拼凑了一个解决方案。

您可以Compile表达式在其中生成runnable函数。

Dim func = lambda.Compile()
Dim output = func(Me)

由于我仍然在通过lambdas工作,所以通过解释再说一点:

在Expression中,我们声明函数签名看起来像这样Func(Of T, Object)
当我们调用该方法时,我们告诉函数评估的行为类似于x => x.Bar.Car

编译将为我们提供一个新函数,存储为局部变量,其行为如下:

Function Anonymous(x as T) As Object
    Return x.Bar.Car
End

所以我们实际上还没有真正通过实例。我们刚刚传递了定义,当我们调用这个匿名函数并传入T类型的东西时会发生什么。

所以我们仍然需要引入Me。在这种情况下,因为这个函数恰好位于同一个类中,所以我们作弊了一点,因为该方法已经可以访问实例变量。如果它被抽象出其他地方,则实例本身必须作为附加参数传入。