为什么在VB.NET中传递"Me"ByRef是合法的?

Dan*_*Tao 4 vb.net compiler-construction byref this-pointer

刚才我震惊地发现以下是合法的(C#等价物绝对不是):

Class Assigner
    ''// Ignore this for now.
    Public Field As Integer

    ''// This part is not so weird... take another instance ByRef,
    ''// assign it to a different instance -- stupid but whatever. '
    Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
        x = y
    End Sub

    ''// But... what's this?!?
    Sub AssignNew()
        ''// Passing "Me" ByRef???
        Assign(Me, New Assigner)
    End Sub

    ''// This is just for testing.
    Function GetField() As Integer
        Return Me.Field
    End Function
End Class
Run Code Online (Sandbox Code Playgroud)

但是,什么是更奇怪,就像我奇怪的是,它似乎并没有什么,我希望:

Dim a As New Assigner With {.Field = 10}

a.AssignNew()

Console.WriteLine(a.GetField())
Run Code Online (Sandbox Code Playgroud)

以上输出"10",而非"0",就像我认为的那样(虽然很自然,这种期望本身也注入了某种恐怖).所以看起来你可以传递Me ByRef,但是编译器以某种方式覆盖(?)行为就好像你已经通过了一样Me ByVal.

  1. 通过为什么合法Me ByRef(是否有一些向后兼容性解释?)
  2. 我是否正确地说编译器会覆盖执行此操作的行为?如果没有,我错过了什么?

ada*_*101 5

似乎编译器将"Me"转换为变量,然后传递ByRef.如果您编译代码,然后使用Reflector打开它,您可以看到发生了什么:

Class Assigner
    ''// Methods
    Public Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
        x = y
    End Sub

    Public Sub AssignNew()
        Dim VB$t_ref$S0 As Assigner = Me
        Me.Assign((VB$t_ref$S0), New Assigner)
    End Sub

    Public Function GetField() As Integer
        Return Me.Field
    End Function


    ''// Fields
    Public Field As Integer
End Class
Run Code Online (Sandbox Code Playgroud)

因此,当您调用AssignNew()时,您将新实例分配给内部生成的变量."a"变量不会被触及,因为它甚至不是函数的一部分.


zin*_*lon 5

这种行为实际上直接来自Visual Basic规范.

11.4.3实例表达式

实例表达式是关键字Me,MyClassMyBase.实例表达式(可能仅在非共享方法,构造函数或属性访问器的主体内使用)被归类为.

9.2.5.2参考参数

如果传递给引用参数的变量类型与引用参数的类型不兼容,或者将非变量作为参数传递给引用参数,则可以分配临时变量并将其传递给引用参数.传入的值将在调用方法之前复制到此临时变量中,并在方法返回时将其复制回原始变量(如果有).

(都强调我的)

因此,编译器将创建一个临时变量,该变量分配Me给要作为ByRef参数传递的值.返回时,不会产生结果值的副本,因为Me它不是变量.