Иллюстрированный самоучитель по Visual Basic .NET

Проблемы с передачей объектных переменных по значению

Большинство языков программирования требует четкого понимания, чем передача параметров по ссылке отличается от передачи по значению. Не забывайте, что в VB.NET параметры по умолчанию передаются по значению (ByVal).

Большинство программистов руководствуется простым правилом: если параметр передавался по ссылке, его изменения сохраняются в исходной переменной, а если по значению – изменения теряются после выхода из функции или процедуры. К сожалению, в случае с объектными переменными это правило не всегда истинно. Попробуйте выполнить следующий фрагмент, в котором массив передается в процедуру по значению. Вы убедитесь в том, что исходный массив изменяется после вызова процедуры!

Module Modulel Sub Main()
Dim a() As String ={"HELLO"."GOODBYE"}
Console.WriteLineC'Original first item in array is:" & a(0))
Console.WriteLineC'Original second item in array is:" & a(1))
Yikes(a) ' Массив передается по значению!
Console.WriteLineC'After passing by value first item in array now is:"_
&A(0))
Console.WriteLine("After passing by value second item in array is:"_
&А(1))
Console. ReadLine()
End Sub
Sub Yikes(ByVal Foo As String())
Foo(0) = "GOODBYE"
Food) = "HELLO"
End Sub
End Module

Иллюстрированный самоучитель по Visual Basic .NET › Классы и объекты › Проблемы с передачей объектных переменных по значению
Рис. 4.7. Результат работы тестовой программы

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

Главная причина заключается в том, что при передаче по значению всегда создается новая копия исходной переменной; после выхода из функции эта копия уничтожается. Но, передавая по значению объектную переменную, вы приказываете VB.NET создать копию манипулятора для работы с объектом. Внутри процедуры операции с временным манипулятором отражаются на содержимом этой области памяти. После вызова из процедуры копия уничтожается, но все изменения в содержимом памяти остаются в силе.

Представьте себе чемодан, к которому временно приделали вторую ручку. Вы перенесли чемодан за новую ручку на другое место; даже если теперь отсоединить ручку, чемодан все равно останется на новом месте.

В этой странной ситуации есть лишь одно исключение – когда исходный объект является неизменяемым (immutable). Из стандартных, постоянно используемых классов к этой категории относится только класс String. В этом случае передача по значению работает именно так, как положено, в чем нетрудно убедиться при помощи следующей программы:

Option Strict On Module Modulel Sub Main()
Dim A As String = "hello"
NoProblem(A)
Console.WriteLine("After passing by value the string is still " & A)
Console. ReadLine()
End Sub
Sub NoProblem(ByVal Foo As String)
Foo = "goodbye"
End Sub
End Module

Примечание
B VB.NET существуют так называемые структурные типы (value types), к числу которых относятся обычные числа, даты и перечисляемые типы (программист также может определять собственные структурные типы, как будет показано далее в этой главе). Для структурных типов передача по значению работает вполне традиционно. Странная ситуация, описанная выше, возникает только при передаче по значению изменяемых ссылочных типов
.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.