Expression(Of Func(Of T)).Body.Member.Name古怪的"$ vb $ local_"如果在属性获取访问器中使用,则添加 [英] Expression(Of Func(Of T)).Body.Member.Name bizarre "$vb$local_" added if used inside a Property Get Accessor
问题描述
我已经观察到以下奇怪的行为,并想看看是否有人曾经遇到过同样的情况.实际上,我做了很多搜索,但还没有发现任何相关内容.
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.
通过Lambda表达式,从类到方法中提供对属性名称的引用已经有了某种常规,而不是名称String本身.因此:RaisePropertyChanged("myProperty")
在C#中为RaisePropertyChanged(() => myProperty)
,在VB .Net中为RaisePropertyChanged(Function() myProperty)
.
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.
被调用的方法在C#中以System.Linq.Expressions.Expression<Func<T>>
类型在VB .Net中以System.Linq.Expressions.Expression<Func<T>>
类型接收该Lambda表达式.
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.
为了以字符串表示形式获取属性名称,被调用的方法将Expression(Of Func(Of T)).Body
检索为MemberExpression
.然后访问memberExprisson.Member.Name
通常将获得正确的属性名称.
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.
但是,在VB .Net中,我注意到以下奇怪的行为:当调用Property内部的方法时,通过(Function() myProperty)
之类的方法提供属性的Get存根会导致memberExprisson.Member.Name
结果为:"$ VB $ Local_myProperty".因此,在属性名称之前添加了$ VB $ Local_.但是,从属性集"存根中进行调用可以按预期进行.
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.
此外,当结果为OK时,memberExpression.Member
'类型为System.Reflection.RuntimePropertyInfo
.而当添加奇怪的"$ VB $ Local_"时,memberExpression.Member
会导致System.Reflection.RtFieldInfo
类型.
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.
在检查上述memberExpression
的Expression属性时,发现:memberExpression.Expression
,我发现其Type
属性将-具有良好的行为-具有正确的容器类名称.但是,在错误行为下,该Type属性将具有"FullName"属性,例如"_Closure $ __ X" +容器(声明)类名称.进一步查看此Type属性的内部,可以发现此FullName由类型本身的名称组成,该名称本身是"_Closure $ __ X",再加上包含正确类名称的'ReflectedType',从而导致此奇怪的FullName.顺便说一下,此"_Closure $ __ X",'X'代表数字.在第一个属性获取"存根中将为"1",第二个将为2,依此类推.因此:"_ Closure $ __ 1","_ Closure $ __ 2" ...
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"...
有任何评论吗?
为清楚起见,下面是代码的快照:
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
和SetProperty
在以下代码中定义:
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
希望这会有所帮助.
推荐答案
如果您还记得表达式主要用于什么,那么这很有意义:表达式通常用于编译为函数.获取属性内引用自己的表达式将编译为无限循环.因此,该lambda不再是PropertyExpression
,而是成为了闭包上的FieldExpression
:
If you remember what Expressions are primarily used for, this makes sense: Expressions are generally used to compile into functions. An expression inside a Get Property that references itself would compile into an infinite loop. So instead of that lambda becoming a PropertyExpression
, it becomes a FieldExpression
on a closure:
GetProperty(Of Result)(Function() RegisteredServer)
与GetProperty(Of Result)(Function() Me.RegisteredServer)
相同,因此编译器将'this'(Me
)引用括起来.闭包周围的字段表达式可能会导致访问由编译器生成的具有奇怪名称的类.
GetProperty(Of Result)(Function() RegisteredServer)
is the same GetProperty(Of Result)(Function() Me.RegisteredServer)
, so the compiler encloses the 'this' (Me
) reference. A field expression around a closure can result in accessing a compiler-generated class, with weird names.
在您的情况下,您实际上并不在乎"this"引用,您只想采用一种强类型引用属性的方法.您可以通过添加一个显式参数来做到这一点,这样就不会包含任何内容:
In your case, you don't really care about the 'this' reference, you just want a way to reference the Property in a strongly-typed way. You can do this by adding an explicit parameter so you're not enclosing anything:
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
类型变量:
Edit:
Upon further thought, you don't need the TClass
type variable:
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(Function(c) c.RegisteredServer)
.代替GetProperty(Of Result)(Function() RegisteredServer)
或GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)
.
... where X
is the name of your class. This means you can remove the type annotations from your GetProperty
calls: So instead of GetProperty(Of Result)(Function() RegisteredServer)
or GetProperty(Of YourClass, Result)(Function(c) c.RegisteredServer)
, you can now do: GetProperty(Function(c) c.RegisteredServer)
.
这篇关于Expression(Of Func(Of T)).Body.Member.Name古怪的"$ vb $ local_"如果在属性获取访问器中使用,则添加的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!