vb.netbyrefthis-pointer

Why is it legal to pass "Me" ByRef in VB.NET?


I was shocked just a moment ago to discover that the following is legal (the C# equivalent is definitely not):

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

But what's even stranger just as strange to me is that it doesn't seem to do what I expect:

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

a.AssignNew()

Console.WriteLine(a.GetField())

The above outputs "10," not "0" like I thought it would (though naturally, this expectation was itself infused with a certain kind of horror). So it seems that you can pass Me ByRef, but the behavior is somehow overridden (?) by the compiler to be as if you had passed Me ByVal.

  1. Why is it legal to pass Me ByRef? (Is there some backwards-compatibility explanation?)
  2. Am I correct in saying that the behavior of doing this is overridden by the compiler? If not, what am I missing?

Solution

  • This behavior actually follows pretty directly from the Visual Basic specification.

    11.4.3 Instance Expressions

    An instance expression is the keyword Me, MyClass, or MyBase. An instance expression, which may only be used within the body of a non-shared method, constructor, or property accessor, is classified as a value.

    9.2.5.2 Reference Parameters

    If the type of the variable being passed to a reference parameter is not compatible with the reference parameter's type, or if a non-variable is passed as an argument to a reference parameter, a temporary variable may be allocated and passed to the reference parameter. The value being passed in will be copied into this temporary variable before the method is invoked and will be copied back to the original variable (if there is one) when the method returns.

    (All emphasis mine)

    So, the compiler will create a temporary variable assigned to the value of Me to be passed as the ByRef parameter. Upon return, no copy of the resulting value will take place since Me is not a variable.