VB6 передается по значению и проходит по ссылке

Я изо всех сил пытаюсь понять, передать по значению и передать по ссылке в VB6. Я полностью понимаю эти концепции в объектно-ориентированных языках программирования, таких как .NET и Java (я понимаю, что Java не имеет ссылки). Посмотрите на код ниже:

Private Sub Form_Load()

Dim Test As Integer
Test = 1
TestFunction Test 'line 5
MsgBox (Test)

End Sub

Private Sub TestFunction(ByVal i As Integer)
    i = i + 1
End Sub

Когда я ставлю скобки вокруг Test в строке 5, в окне сообщения выводится 1, как я и ожидал. Теперь взгляните на код ниже:

Private Sub Form_Load()

Dim Test As Integer
Test = 1
TestFunction Test 'line 5
MsgBox Test

End Sub

Private Sub TestFunction(ByRef i As Integer)
    i = i + 1
End Sub

Окно сообщения печатает 2, как я и ожидал. Однако, если вы добавите скобки в строку 5, в окне сообщения будет напечатано 1, чего я не ожидал. Похоже, что вызывающая функция может передаваться по значению, даже если переменная, определенная в вызываемой функции, является ByRef. Похоже, что это не так, т.е. если вызываемая функция имеет сигнатуру с переменной, определенной как ByVal, то она всегда будет ByVal (даже если в вызывающей функции нет скобок вокруг переменной). Что стоит за этим в VB6? Я понимаю, что это основной вопрос в VB6, но он смутил меня. Я прочитал документацию MSDN и понял, что это все правда, однако он не объясняет причины этого.

Ответ 1

Это классическая игра в VB6. Это объяснено в руководстве VB6. В этом коде ниже VB6 рассматривает аргумент как выражение (Test), а не ссылку на переменную

TestFunction (Test)

Чтобы передать ссылку на переменную, опустите скобки или используйте устаревший Call statement (для чего требуются скобки)

TestFunction Test
Call TestFunction(Test)

VB6 позволяет передавать выражения в аргументы ByRef, даже если метод их изменяет. Например, вы можете написать

TestFunction (Test + 2)

Компилятор создает временную копию и передает ее по ссылке. VB.Net использует скобки аналогичным образом.

Вы также можете получить компилятор для создания временных копий, если TestFunction принимает два аргумента, например:

TestFunction (one), (two)

И вы можете получить временные копии даже при Call, если вы удвоите свои скобки, добавив лишнюю лишнюю пару:

Call TestFunction((Test))

Ответ 2

Включение любого выражения в круглые скобки приводит к тому, что выражение сначала оценивается, прежде чем делать что-либо еще, даже если это выражение является только одной переменной. В вашем случае результат этого выражения затем передается в качестве аргумента.

Итак, вы фактически передаете аргумент по ссылке. Но аргумент, который вы передаете, является результатом выражения, а не исходной переменной. Вот почему исходная переменная не обновляется.