我正在尝试为一个类构建一个字符串,该类包含该属性的所有属性名称及其各自值的列表。
根据问题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)
任何想法?
答案 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
。在这种情况下,因为这个函数恰好位于同一个类中,所以我们作弊了一点,因为该方法已经可以访问实例变量。如果它被抽象出其他地方,则实例本身必须作为附加参数传入。