Упражнение. Использование параметров значения и ссылочного типа
В C#переменные можно классифицировать по двум основным типам, типам значений и ссылочным типам. Эти типы описывают, как переменные хранят их значения.
Типы значений, такие как int, bool, floatdoubleи char напрямую содержат значения. Ссылочные типы, такие как string, arrayи объекты (например, экземпляры Random) не хранят их значения напрямую. Вместо этого ссылочные типы хранят адрес, в котором хранится их значение.
Параметры, передаваемые по значению и передаваемые по ссылке
При передаче аргумента в метод переменные типа значений копируются в метод. Каждая переменная имеет собственную копию значения, поэтому исходная переменная не изменяется.
С ссылочными типами адрес значения передается в метод. Переменная, указанная методу, ссылается на значение по указанному адресу, поэтому операции с этой переменной влияют на значение, на которое ссылается другая.
Замечание
Важно помнить, что string это ссылочный тип, но это неизменяемый. Это означает, что после назначения значения его нельзя изменить. В C#, когда методы и операторы используются для изменения строки, возвращаемый результатом фактически является новый строковый объект.
В этом упражнении вы узнаете больше о передаче аргументов ссылочного типа и значимых типов в методы.
Проверка прохождения по значению
В редакторе Visual Studio Code удалите существующий код из предыдущих упражнений.
Введите следующий код в редактор Visual Studio Code:
int a = 3; int b = 4; int c = 0; Multiply(a, b, c); Console.WriteLine($"global statement: {a} x {b} = {c}"); void Multiply(int a, int b, int c) { c = a * b; Console.WriteLine($"inside Multiply method: {a} x {b} = {c}"); }Переменные
aиbcпередаются методуMultiply. Значения переменных печатаются во время выполнения метода и печатаются снова после завершения метода.Целые числа — это типы значений, которые копируются при передаче в методы. Как вы думаете, каков будет выход
c?Сохраните и запустите код, чтобы просмотреть следующие выходные данные:
inside Multiply method: 3 x 4 = 12 global statement: 3 x 4 = 0Обратите внимание, что значение
cизменено только в методеMultiply. За пределами методаcсохраняет исходное значение.
Тестовый проход по ссылке
Удалите предыдущий код из редактора Visual Studio Code.
Введите следующий код в редактор Visual Studio Code:
int[] array = {1, 2, 3, 4, 5}; PrintArray(array); Clear(array); PrintArray(array); void PrintArray(int[] array) { foreach (int a in array) { Console.Write($"{a} "); } Console.WriteLine(); } void Clear(int[] array) { for (int i = 0; i < array.Length; i++) { array[i] = 0; } }Код начинается с
arrayинициализации, чтобы содержать некоторые целые значения. Значения отображаются с помощьюPrintArrayметода. МетодClearвызывается в массиве, а затем повторно выводится массив.Массивы являются ссылочными типами. Ссылочные типы хранят адрес своих значений в памяти. Как вы думаете, каким будет результат?
Сохраните и запустите код, чтобы просмотреть следующие выходные данные:
1 2 3 4 5 0 0 0 0 0Обратите внимание, что массив остается изменен вне
Clearобласти метода. Это происходит, так какClearметод обновляет значения, хранящиеся в каждом адресе.
Тестирование с помощью строк
Ранее вы узнали, что строки являются неизменяемым типом. Несмотря на то, что строка является ссылочным типом, его значение не может быть изменено после его назначения, в отличие от массива. Возможно, вы заметили это, если вы использовали такие методы, как string.Replace или string.ToUpper. В этой задаче вы узнаете, как исправить общую ошибку при работе со строками.
В редакторе Visual Studio Code удалите существующий код из предыдущих упражнений.
Введите следующий код в редактор Visual Studio Code:
string status = "Healthy"; Console.WriteLine($"Start: {status}"); SetHealth(status, false); Console.WriteLine($"End: {status}"); void SetHealth(string status, bool isHealthy) { status = (isHealthy ? "Healthy" : "Unhealthy"); Console.WriteLine($"Middle: {status}"); }Сохраните и запустите код, чтобы просмотреть следующие выходные данные:
Start: Healthy Middle: Unhealthy End: HealthyЕсли метод
SetHealthне вывел статус, вы могли предположить, что метод не выполнен правильно. Вместо этого была создана новая строка со значением "Нездоровая", которая затем была утеряна в области метода.Чтобы устранить эту проблему, можно изменить
SetHealth, чтобы использовать глобальную переменную состояния.Внесите в код следующие изменения.
string status = "Healthy"; Console.WriteLine($"Start: {status}"); SetHealth(false); Console.WriteLine($"End: {status}"); void SetHealth(bool isHealthy) { status = (isHealthy ? "Healthy" : "Unhealthy"); Console.WriteLine($"Middle: {status}"); }В этом коде вы перезаписываете глобальную
statusпеременную новым строковым значением.Сохраните и запустите код, чтобы просмотреть следующие выходные данные:
Start: Healthy Middle: Unhealthy End: UnhealthyТеперь обновленная строка записывается и хранится правильно.
Обзор
Вот что вы узнали о типах значений и параметрах ссылочного типа до сих пор:
- Переменные можно классифицировать как типы значений и ссылочные типы.
- Типы значений напрямую содержат значения, а ссылочные типы хранят адрес значения.
- Методы, использующие аргументы типа значений, создают собственную копию значений.
- Методы, выполняющие изменения в параметре массива, влияют на исходный входной массив.
- Строка — это неизменяемый ссылочный тип.
- Методы, выполняющие изменения в строковом параметре, не влияют на исходную строку.