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

查看:64
本文介绍了Expression(Of Func(Of T)).Body.Member.Name古怪的"$ vb $ local_"如果在属性获取访问器中使用,则添加的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经观察到以下奇怪的行为,并想看看是否有人曾经遇到过同样的情况.实际上,我做了很多搜索,但还没有发现任何相关内容.

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.Nameresults 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

GetPropertySetProperty在以下代码中定义:

GetPropertyAnd 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆