我观察到以下奇怪的行为,并想看看是否有人已经遇到过同样的事情。事实上,我做了很多搜索,但还没有碰到任何相关内容。
以某种方式,通过Lambda表达式提供对类中的属性名称的引用,而不是名称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表达式。
为了在String表示中获取Property属性,被调用的Method将Expression(Of Func(Of T)).Body
检索为MemberExpression
。然后访问memberExprisson.Member.Name
通常会获得正确的属性名称。
然而,在VB .Net中我注意到以下奇怪的行为:当调用Property Get内部的方法时,通过诸如(Function() myProperty)
之类的方式提供属性,memberExprisson.Member.Name
结果为:“$ VB $ Local_myProperty”。所以在属性名称前添加了$ VB $ Local_。然而,从Property Set存根调用按预期工作。
更重要的是,当结果正常时,memberExpression.Member
'类型为System.Reflection.RuntimePropertyInfo
。而当添加奇怪的“$ VB $ Local_”时,memberExpression.Member
会产生System.Reflection.RtFieldInfo
类型。
当检查上面提到的memberExpression
的表达式属性时,memberExpression.Expression
,我发现其Type
属性 - 在良好行为上 - 具有正确的容器类名称。但是,在错误行为中,Type属性将具有类似“_Closure $ __ X”+容器(声明)类名称的“FullName”属性。进一步查看此Type属性会显示此FullName由Type本身的Name组成,其中“_Closure $ __ X”与包含正确Class Name的'ReflectedType'相结合,从而产生这个奇怪的FullName。顺便说一句,这是“_Closure $ __ X”,'X'代表一个数字。它将在第一个Property Get存根中为'1',为第二个存在时为2,依此类推。所以:“_ Close $ __ 1”,“_ Close $ __ 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
希望这有帮助。
答案 0 :(得分:2)
如果你还记得主要用于表达式,这是有道理的:表达式通常用于编译成函数。 Get属性中引用自身的表达式将编译为无限循环。因此,而不是lambda成为PropertyExpression
,它在闭包上变为FieldExpression
:
GetProperty(Of Result)(Function() RegisteredServer)
与GetProperty(Of Result)(Function() Me.RegisteredServer)
相同,因此编译器会将&#39;这个&#39;包含在内。 (Me
)参考。闭包周围的字段表达式可能导致访问编译器生成的类,名称很奇怪。
在你的情况下,你并不真正关心这个&#39;这个&#39;参考,您只想要一种以强类型方式引用Property的方法。您可以通过添加显式参数来执行此操作,这样您就不会包含任何内容:
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
是您班级的名称。这意味着您可以从GetProperty
来电中删除类型注释:现在您可以执行以下操作:GetProperty(Of Result)(Function() RegisteredServer)
或GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)
,而不是GetProperty(Function(c) c.RegisteredServer)
或{{1}}。