Важно понимать, что все в C # передается значением , если вы не укажете ref
или out
в подписи.
Что отличает типы значений (и, следовательно, struct
s) от ссылочных типов, так это то, что доступ к типу значений осуществляется напрямую, а ссылочный тип - через его ссылку. Если вы передаете ссылочный тип в метод, его ссылка , а не само значение, передается по значению.
Чтобы проиллюстрировать это, представьте, что у нас есть класс PointClass
и struct PointStruct
, определенные аналогично (без учета несущественных деталей):
struct PointStruct { public int x, y; }
class PointClass { public int x, y; }
И у нас есть метод SomeMethod
, который принимает эти два типа по значению :
static void ExampleMethod(PointClass apc, PointStruct aps) { … }
Если мы сейчас создадим два объекта и вызовем метод:
var pc = new PointClass(1, 1);
var ps = new PointStruct(1, 1);
ExampleMethod(pc, ps);
… мы можем представить это на следующей диаграмме:
Поскольку pc
является ссылкой, оно не содержит само значение; скорее он ссылается на (неназванное) значение где-то еще в памяти. Это видно по пунктирной границе и стрелке.
Но: для pc
и ps
, фактическая переменная копируется при вызове метода.
Что произойдет, если ExampleMethod
переназначит переменные аргумента внутренне? Давайте проверим:
static void ExampleMethod(PointClass apc, PointStruct aps); {
apc = new PointClass(2, 2);
aps = new PointStruct(2, 2);
}
Вывод pc
и ps
после вызова метода:
pc: {x: 1, y: 1}
ps: {x: 1, y: 1}
→ ExampleMethod
изменил копию значений, и исходные значения не изменились.
По сути, это то, что означает «передача по значению».
Все еще существует разница между ссылочным типом и типом значения, и это проявляется при изменении членов значения, а не самой переменной. Это та часть, которая сбивает людей с толку, когда они сталкиваются с тем фактом, что ссылочные типы передаются по значению. Рассмотрим другой ExampleMethod
.
static void ExampleMethod(PointClass apc, PointStruct aps) {
apc.x = 2;
aps.x = 2;
}
Теперь мы наблюдаем следующий результат после вызова метода:
pc: {x: 2, y: 1}
ps: {x: 1, y: 1}
→ Ссылочный объект был изменен, тогда как объект значения не был. Приведенная выше диаграмма показывает, почему это так: для эталонного объекта, даже если pc
было скопировано, фактическое значение, которое как pc
, так и apc
эталон, остается идентичным, и мы можем изменить его с помощью apc
. Что касается ps
, мы скопировали само фактическое значение в aps
; исходное значение не может быть затронуто ExampleMethod
.