Передача аргументов по значению и по ссылке (Visual Basic)

В Visual Basic можно передать аргумент в процедуру по значению или по ссылке. Это называется механизмом передачи и определяет, может ли процедура изменить программный элемент, лежащий в основе аргумента в вызывающем коде. Объявление процедуры определяет механизм передачи для каждого параметра, указывая ключевое слово ByVal или ByRef.

Различия

При передаче аргумента в процедуру следует учитывать несколько различий, которые взаимодействуют друг с другом:

  • Является ли базовый программный элемент изменяемым или неизменяемым

  • Указывает, является ли сам аргумент изменяемым или неизменяемым

  • Указывает, передается ли аргумент по значению или по ссылке

  • Тип данных аргумента является типом значения или ссылочным типом

Дополнительные сведения см. в разделах Различия между изменяемыми и неизменяемыми аргументами и Различия между передачей аргумента по значению и по ссылке.

Выбор механизма передачи

Для каждого аргумента следует тщательно выбирать механизм передачи.

  • Защита. При выборе между двумя механизмами передачи наиболее важным критерием является возможность изменения вызывающих переменных. Преимущество передачи аргумента ByRef заключается в том, что процедура может возвращать значение в вызывающий код через этот аргумент. Преимущество передачи аргумента ByVal заключается в том, что он защищает переменную от изменения процедурой.

  • Производительность. Хотя механизм передачи может повлиять на производительность кода, разница обычно незначительна. Одним из исключений из этого является переданный ByValтип значения . В этом случае Visual Basic копирует все содержимое аргумента . Таким образом, для большого типа значения, такого как структура, может быть эффективнее передать его ByRef.

    Для ссылочных типов копируется только указатель на данные (четыре байта на 32-разрядных платформах и восемь байтов на 64-разрядных платформах). Поэтому можно передавать аргументы типа String или Object по значению без ущерба для производительности.

Определение механизма передачи

Объявление процедуры задает механизм передачи для каждого параметра. Вызывающий код не может переопределить ByVal механизм.

Если параметр объявлен с ByRefпараметром , вызывающий код может принудительно принудить механизм к ByVal , заключив имя аргумента в круглые скобки в вызове . Дополнительные сведения см. в разделе Практическое руководство. Принудительная передача аргумента по значению.

По умолчанию в Visual Basic аргументы передаются по значению.

Время передачи аргумента по значению

  • Если вызывающий элемент кода, лежащий в основе аргумента, является неизменяемым элементом, объявите соответствующий параметр ByVal. Никакой код не может изменить значение неизменяемого элемента.

  • Если базовый элемент является изменяемым, но вы не хотите, чтобы процедура могла изменять свое значение, объявите параметр ByVal. Только вызывающий код может изменить значение изменяемого элемента, передаваемого по значению.

Время передачи аргумента по ссылке

  • Если процедуре действительно необходимо изменить базовый элемент в вызывающем коде, объявите соответствующий параметр ByRef.

  • Если правильное выполнение кода зависит от процедуры изменения базового элемента в вызывающем коде, объявите параметр ByRef. Если передать его по значению или вызывающий код переопределяет ByRef механизм передачи, заключив аргумент в круглые скобки, вызов процедуры может привести к непредвиденным результатам.

Пример

Описание

В следующем примере показано, когда следует передавать аргументы по значению, а когда передавать их по ссылке. В процедуре CalculateByVal есть параметр и ByRef . Учитывая процентную ставку rateи сумму денег, задача процедуры состоит в том, debtчтобы вычислить новое значение для debt , которое является результатом применения процентной ставки к исходному значению debt. Так как debt является параметром ByRef , новое итоговое значение отражается в значении аргумента в вызывающем коде, соответствующему debt. Параметр rate является параметром, ByVal так как Calculate не должен изменять его значение.

Код

Module Module1

    Sub Main()
        ' Two interest rates are declared, one a constant and one a 
        ' variable.
        Const highRate As Double = 12.5
        Dim lowRate = highRate * 0.6

        Dim initialDebt = 4999.99
        ' Make a copy of the original value of the debt.
        Dim debtWithInterest = initialDebt

        ' Calculate the total debt with the high interest rate applied.
        ' Argument highRate is a constant, which is appropriate for a 
        ' ByVal parameter. Argument debtWithInterest must be a variable
        ' because the procedure will change its value to the calculated
        ' total with interest applied.
        Calculate(highRate, debtWithInterest)
        ' Format the result to represent currency, and display it.
        Dim debtString = Format(debtWithInterest, "C")
        Console.WriteLine("What I owe with high interest: " & debtString)

        ' Repeat the process with lowRate. Argument lowRate is not a 
        ' constant, but the ByVal parameter protects it from accidental
        ' or intentional change by the procedure. 

        ' Set debtWithInterest back to the original value.
        debtWithInterest = initialDebt
        Calculate(lowRate, debtWithInterest)
        debtString = Format(debtWithInterest, "C")
        Console.WriteLine("What I owe with low interest:  " & debtString)
    End Sub

    ' Parameter rate is a ByVal parameter because the procedure should
    ' not change the value of the corresponding argument in the 
    ' calling code. 

    ' The calculated value of the debt parameter, however, should be
    ' reflected in the value of the corresponding argument in the 
    ' calling code. Therefore, it must be declared ByRef. 
    Sub Calculate(ByVal rate As Double, ByRef debt As Double)
        debt = debt + (debt * rate / 100)
    End Sub

End Module

См. также раздел