Expression(Of Func(Of T)).Body.Member.Name 如果在 属性 Get 访问器中使用,则添加奇怪的“$vb$local_”
Expression(Of Func(Of T)).Body.Member.Name bizarre "$vb$local_" added if used inside a Property Get Accessor
我观察到以下奇怪的行为,想看看是否有人遇到过同样的情况。事实上,我做了很多搜索,但还没有碰到任何相关的东西。
通过 Lambda 表达式从 Class 中向方法提供对 属性 名称的引用,而不是名称 String 本身,这在某种程度上已经变得非常传统。所以:RaisePropertyChanged("myProperty")
在 C# 中得到 RaisePropertyChanged(() => myProperty)
或在 VB .Net 中得到 RaisePropertyChanged(Function() myProperty)
。
被调用方法在 C# 中的 System.Linq.Expressions.Expression<Func<T>>
类型或 VB .Net 中的 Expression(Of Func(Of T))
中接收 Lambda 表达式。
为了在字符串表示中获取 属性 名称,被调用的方法将 Expression(Of Func(Of T)).Body
作为 MemberExpression
检索。然后访问 memberExprisson.Member.Name
通常会得到正确的 属性 名称。
但是,在 VB .Net 中,我注意到以下奇怪的行为:在 属性 中调用方法时,通过 [=23] 等方式获取提供 属性 的存根=] memberExprisson.Member.Name
结果为:“$VB$Local_myProperty”。所以在 属性 名称前面添加了 $VB$Local_。然而,从 属性 Set 存根调用按预期工作。
而且,当结果OK时,memberExpression.Member
'类型是System.Reflection.RuntimePropertyInfo
。而当添加奇怪的“$VB$Local_”时,memberExpression.Member
会导致 System.Reflection.RtFieldInfo
类型。
当检查上述 memberExpression
的表达式 属性 时:memberExpression.Expression
,我发现其中的 Type
属性 会 - 很好行为 - 具有正确的 Container Class 名称。然而,在错误行为中,该类型 属性 将具有类似“_Closure$__X”的 'FullName' 属性 + 容器(声明)Class 名称。进一步查看此类型 属性 会发现此 FullName 由类型本身的名称“_Closure$__X”与包含正确 [=67= 的 'ReflectedType' 组合而成] 名称,导致这个奇怪的全名。这个“_Closure$__X” 顺便说一句,'X'代表一个Number。它将在第一个 属性 Get stub 中为“1”,第二个为 2,依此类推。所以:“_Closure$__1”,“_Closure$__2”...
有意见吗?
编辑:
为清楚起见,这里是代码的快照:
Public Property RegisteredServer As Result
Get
Return GetProperty(Of Result)(Function() RegisteredServer)
End Get
Set(value As Result)
SetProperty(Of Result)(Function() RegisteredServer, value)
End Set
End Property
Public Property DefaultInstance As Result
Get
Return GetProperty(Function() DefaultInstance)
End Get
Set(value As Result)
SetProperty(Function() DefaultInstance, value)
End Set
End Property
GetProperty
和SetProperty
定义如下代码:
Private Function GetPropertyName(Of T)(propertyExpression As Expression(Of Func(Of T)))
Dim memberExpr As MemberExpression = propertyExpression.Body
If memberExpr Is Nothing Then
Throw New ArgumentException("propertyExpression should represent access to a member")
End If
Dim memberName As String = memberExpr.Member.Name
Return memberName
End Function
Shared Function CompareValues(Of T)(storage As T, value As T)
Return Object.Equals(storage, value)
End Function
Protected Function SetProperty(Of T)(propertyExpression As Expression(Of Func(Of T)), value As T)
Dim memberName As String = GetPropertyName(propertyExpression)
Dim currentValue As T = Nothing
_propertyBag.TryGetValue(memberName, currentValue)
If CompareValues(currentValue, value) Then
Return False
End If
_propertyBag(memberName) = value
RaisePropertyChanged(memberName)
Return True
End Function
Protected Function GetProperty(Of T)(propertyExpression As Expression(Of Func(Of T))) As T
Dim memberName As String = GetPropertyName(propertyExpression)
Dim value As T = Nothing
_propertyBag.TryGetValue(memberName, value)
Return value
End Function
希望对您有所帮助。
如果您还记得表达式的主要用途,那么这是有道理的:表达式通常用于编译成函数。引用自身的 Get 属性 中的表达式将编译成无限循环。因此,不是那个 lambda 变成 PropertyExpression
,而是在闭包上变成 FieldExpression
:
GetProperty(Of Result)(Function() RegisteredServer)
与 GetProperty(Of Result)(Function() Me.RegisteredServer)
相同,因此编译器附上了 'this' (Me
) 引用。闭包周围的字段表达式可能会导致访问编译器生成的 class,名称很奇怪。
在您的情况下,您并不真正关心 'this' 引用,您只是想要一种以强类型方式引用 属性 的方法。你可以通过添加一个显式参数来做到这一点,这样你就不会包含任何东西:
Public Function GetPropertyName(Of TClass, TProperty)(propertyExpression As Expression(Of Func(Of TClass, TProperty)))
Dim memberExpr As MemberExpression = propertyExpression.Body
If memberExpr Is Nothing Then
Throw New ArgumentException("propertyExpression should represent access to a member")
End If
Dim memberName As String = memberExpr.Member.Name
Return memberName
End Function
Protected Function GetProperty(Of TClass, TProperty)(propertyExpression As Expression(Of Func(Of TClass, TProperty))) As TProperty
Dim memberName As String = GetPropertyName(propertyExpression)
Dim value As TProperty = Nothing
_propertyBag.TryGetValue(memberName, value)
Return value
End Function
...然后 GetProperty(Of Result)(Function() RegisteredServer)
变为 GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)
。
编辑:
经过进一步思考,您不需要 TClass
类型变量:
Public Function GetPropertyName(Of T)(propertyExpression As Expression(Of Func(Of X, T)))
Dim memberExpr As MemberExpression = propertyExpression.Body
If memberExpr Is Nothing Then
Throw New ArgumentException("propertyExpression should represent access to a member")
End If
Dim memberName As String = memberExpr.Member.Name
Return memberName
End Function
Protected Function GetProperty(Of TProperty)(propertyExpression As Expression(Of Func(Of X, TProperty))) As TProperty
Dim memberName As String = GetPropertyName(propertyExpression)
Dim value As TProperty = Nothing
_propertyBag.TryGetValue(memberName, value)
Return value
End Function
... 其中 X
是您的 class 的名称。这意味着您可以从 GetProperty
调用中删除类型注释:因此,您现在可以执行 GetProperty(Function(c) c.RegisteredServer)
.
而不是 GetProperty(Of Result)(Function() RegisteredServer)
或 GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)
我观察到以下奇怪的行为,想看看是否有人遇到过同样的情况。事实上,我做了很多搜索,但还没有碰到任何相关的东西。
通过 Lambda 表达式从 Class 中向方法提供对 属性 名称的引用,而不是名称 String 本身,这在某种程度上已经变得非常传统。所以:RaisePropertyChanged("myProperty")
在 C# 中得到 RaisePropertyChanged(() => myProperty)
或在 VB .Net 中得到 RaisePropertyChanged(Function() myProperty)
。
被调用方法在 C# 中的 System.Linq.Expressions.Expression<Func<T>>
类型或 VB .Net 中的 Expression(Of Func(Of T))
中接收 Lambda 表达式。
为了在字符串表示中获取 属性 名称,被调用的方法将 Expression(Of Func(Of T)).Body
作为 MemberExpression
检索。然后访问 memberExprisson.Member.Name
通常会得到正确的 属性 名称。
但是,在 VB .Net 中,我注意到以下奇怪的行为:在 属性 中调用方法时,通过 [=23] 等方式获取提供 属性 的存根=] memberExprisson.Member.Name
结果为:“$VB$Local_myProperty”。所以在 属性 名称前面添加了 $VB$Local_。然而,从 属性 Set 存根调用按预期工作。
而且,当结果OK时,memberExpression.Member
'类型是System.Reflection.RuntimePropertyInfo
。而当添加奇怪的“$VB$Local_”时,memberExpression.Member
会导致 System.Reflection.RtFieldInfo
类型。
当检查上述 memberExpression
的表达式 属性 时:memberExpression.Expression
,我发现其中的 Type
属性 会 - 很好行为 - 具有正确的 Container Class 名称。然而,在错误行为中,该类型 属性 将具有类似“_Closure$__X”的 'FullName' 属性 + 容器(声明)Class 名称。进一步查看此类型 属性 会发现此 FullName 由类型本身的名称“_Closure$__X”与包含正确 [=67= 的 'ReflectedType' 组合而成] 名称,导致这个奇怪的全名。这个“_Closure$__X” 顺便说一句,'X'代表一个Number。它将在第一个 属性 Get stub 中为“1”,第二个为 2,依此类推。所以:“_Closure$__1”,“_Closure$__2”...
有意见吗?
编辑:
为清楚起见,这里是代码的快照:
Public Property RegisteredServer As Result
Get
Return GetProperty(Of Result)(Function() RegisteredServer)
End Get
Set(value As Result)
SetProperty(Of Result)(Function() RegisteredServer, value)
End Set
End Property
Public Property DefaultInstance As Result
Get
Return GetProperty(Function() DefaultInstance)
End Get
Set(value As Result)
SetProperty(Function() DefaultInstance, value)
End Set
End Property
GetProperty
和SetProperty
定义如下代码:
Private Function GetPropertyName(Of T)(propertyExpression As Expression(Of Func(Of T)))
Dim memberExpr As MemberExpression = propertyExpression.Body
If memberExpr Is Nothing Then
Throw New ArgumentException("propertyExpression should represent access to a member")
End If
Dim memberName As String = memberExpr.Member.Name
Return memberName
End Function
Shared Function CompareValues(Of T)(storage As T, value As T)
Return Object.Equals(storage, value)
End Function
Protected Function SetProperty(Of T)(propertyExpression As Expression(Of Func(Of T)), value As T)
Dim memberName As String = GetPropertyName(propertyExpression)
Dim currentValue As T = Nothing
_propertyBag.TryGetValue(memberName, currentValue)
If CompareValues(currentValue, value) Then
Return False
End If
_propertyBag(memberName) = value
RaisePropertyChanged(memberName)
Return True
End Function
Protected Function GetProperty(Of T)(propertyExpression As Expression(Of Func(Of T))) As T
Dim memberName As String = GetPropertyName(propertyExpression)
Dim value As T = Nothing
_propertyBag.TryGetValue(memberName, value)
Return value
End Function
希望对您有所帮助。
如果您还记得表达式的主要用途,那么这是有道理的:表达式通常用于编译成函数。引用自身的 Get 属性 中的表达式将编译成无限循环。因此,不是那个 lambda 变成 PropertyExpression
,而是在闭包上变成 FieldExpression
:
GetProperty(Of Result)(Function() RegisteredServer)
与 GetProperty(Of Result)(Function() Me.RegisteredServer)
相同,因此编译器附上了 'this' (Me
) 引用。闭包周围的字段表达式可能会导致访问编译器生成的 class,名称很奇怪。
在您的情况下,您并不真正关心 'this' 引用,您只是想要一种以强类型方式引用 属性 的方法。你可以通过添加一个显式参数来做到这一点,这样你就不会包含任何东西:
Public Function GetPropertyName(Of TClass, TProperty)(propertyExpression As Expression(Of Func(Of TClass, TProperty)))
Dim memberExpr As MemberExpression = propertyExpression.Body
If memberExpr Is Nothing Then
Throw New ArgumentException("propertyExpression should represent access to a member")
End If
Dim memberName As String = memberExpr.Member.Name
Return memberName
End Function
Protected Function GetProperty(Of TClass, TProperty)(propertyExpression As Expression(Of Func(Of TClass, TProperty))) As TProperty
Dim memberName As String = GetPropertyName(propertyExpression)
Dim value As TProperty = Nothing
_propertyBag.TryGetValue(memberName, value)
Return value
End Function
...然后 GetProperty(Of Result)(Function() RegisteredServer)
变为 GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)
。
编辑:
经过进一步思考,您不需要 TClass
类型变量:
Public Function GetPropertyName(Of T)(propertyExpression As Expression(Of Func(Of X, T)))
Dim memberExpr As MemberExpression = propertyExpression.Body
If memberExpr Is Nothing Then
Throw New ArgumentException("propertyExpression should represent access to a member")
End If
Dim memberName As String = memberExpr.Member.Name
Return memberName
End Function
Protected Function GetProperty(Of TProperty)(propertyExpression As Expression(Of Func(Of X, TProperty))) As TProperty
Dim memberName As String = GetPropertyName(propertyExpression)
Dim value As TProperty = Nothing
_propertyBag.TryGetValue(memberName, value)
Return value
End Function
... 其中 X
是您的 class 的名称。这意味着您可以从 GetProperty
调用中删除类型注释:因此,您现在可以执行 GetProperty(Function(c) c.RegisteredServer)
.
GetProperty(Of Result)(Function() RegisteredServer)
或 GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)