В Visual Basic параметры процедур могут передаваться по ссылке (ByRef) или по значению (ByVal). Это влияет на то, будут ли изменения внутри процедуры отражаться на исходной переменной вне процедуры.
История вопроса:
По умолчанию в VB.NET параметры процедур передаются по значению (ByVal), что означает передачу копии значения. Через ByRef передаётся не копия, а ссылка на оригинальную переменную.
Проблема:
Использование некорректного способа передачи приводит к ошибкам — например, при неправильном использовании ByRef процедура может изменять переменные вызывающего кода непреднамеренно или, наоборот, изменения не будут сохранены.
Решение:
ByRef используют, когда требуется вернуть несколько значений или изменить переданную переменную. ByVal — во всех остальных случаях для защиты от нежелательных изменений. Крайне важно явно указывать ByRef только по необходимости.
Пример передачи по значению и по ссылке:
Sub DoubleValue(ByVal x As Integer) x = x * 2 End Sub Sub DoubleValueByRef(ByRef x As Integer) x = x * 2 End Sub Dim a As Integer = 5 DoubleValue(a) ' a по-прежнему 5 DoubleValueByRef(a) ' a теперь равно 10
Ключевые особенности:
Что произойдет с объектом при передаче по ByRef: изменится ли ссылка на объект?
Ответ: Если передавать объект по ByRef и присвоить переменной внутри процедуры новый объект, то исходная переменная вне процедуры тоже будет указывать на новый объект. Если передавать по ByVal, можно менять свойства объекта, но нельзя перенаправить саму ссылку — переменная вне процедуры останется прежней.
Sub ChangeRef(ByRef p As Person) p = New Person() With {.Name = "Другой"} End Sub Sub ChangeVal(ByVal p As Person) p.Name = "Изменено" End Sub Dim pers As New Person With {.Name = "Исходный"} ChangeRef(pers) ' pers теперь новый объект ChangeVal(pers) ' pers — тот же объект, имя изменено
Можно ли использовать ByRef для возврата значения из Function?
Ответ: Нет, ByRef указывается только при передаче параметров, а не для самого возвращаемого значения функции.
Что если объявить аргумент массива с ByVal — можно ли изменить содержимое массива?
Ответ: Да, потому что в VB.NET массив — это ссылочный тип, и несмотря на передачу по ByVal, сама ссылка копируется, а элементы массива (по этой же ссылке) можно изменять внутри процедуры.
В команде один из разработчиков использовал ByRef в алгоритме обработки, и изменение значения в одной части программы неожиданно поменяло состояние переменной, из-за чего модуль перестал работать корректно.
Плюсы: Позволяет изменять данные без уточнения структуры возвращаемого значения
Минусы: Высокий риск неочевидных побочных эффектов, сложно отлаживать баги
Параметры передаются по ByVal, а возврат нескольких значений идет через возвращаемые структуры или Tuple, что делает поведение чётким и удобным.
Плюсы: Легче читать и поддерживать код, меньше багов
Минусы: Иногда требуется создавать дополнительные типы или структуры