I have observed the following bizarre behavior, and want to see if anyone already came across the same. In fact, I did quite a bit of searching, but have not bumped in anything related as yet.
It has somehow got quite conventional to supply a reference to a Property name from within a Class to a Method by means of a Lambda expression, instead the name String itself. So: RaisePropertyChanged("myProperty")
gets RaisePropertyChanged(() => myProperty)
in C# or RaisePropertyChanged(Function() myProperty)
in VB .Net.
The called Method receives that Lambda expression in a System.Linq.Expressions.Expression<Func<T>>
type in C# or Expression(Of Func(Of T))
in VB .Net.
In order the get the Property name in a String representation, the called Method retrieves the Expression(Of Func(Of T)).Body
as a MemberExpression
. Then accessing memberExprisson.Member.Name
will usually get the proper Property name.
However, in VB .Net I have noticed the following bizarre behavior: When calling a method inside of Property Get stub supplying a Property by means such as (Function() myProperty)
the memberExprisson.Member.Name
results to: "$VB$Local_myProperty". So that's $VB$Local_ added in front of the Property name. Calling however from the Property Set stub worked as intended.
Whats more, when the result is OK, the memberExpression.Member
'type is a System.Reflection.RuntimePropertyInfo
. Whereas when the bizarre "$VB$Local_" is added, the memberExpression.Member
results in a System.Reflection.RtFieldInfo
type.
When examining the Expression Property of the above mentioned memberExpression
thus: memberExpression.Expression
, I find that the Type
Property thereof will - on good behavior - have the proper Container Class name. On erroneous behavior however, that Type property will have a 'FullName' Property of something like "_Closure$__X" + the Container (Declaring) Class name. Further looking inside this Type property reveals that this FullName consist of a the Name of the Type itself which is "_Closure$__X" combined with the 'ReflectedType' which contains the proper Class name, resulting in this strange FullName. This "_Closure$__X" by the way, The 'X' represents a Number. It will be '1' inside the first Property Get stub and 2 for the second and so forth. So: "_Closure$__1", "_Closure$__2"...
Any comments?
EDIT:
For clarity here is a snapshot of the code:
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
And SetProperty
are defined in the following code:
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
Hope this helps.