В чем разница между ref, out и in?

Только в различных условиях выполнения? Т.е ref не обязан ничего присваивать и он изменяет основную переменную, переданную в метод в случае изменений. out делает тоже самое, но обязывает что-то присвоить. in разрешает только смотреть переменную.

В теории как своего рода модификаторы доступа можно представить?


Ответы (1 шт):

Автор решения: Швеев Алексей

Все данные 3 ключевых слова передают ссылку (аналогично &T в C++).

Передавая ref в метод мы передаём ссылку на участок памяти со значением этой переменной, и изменяя это переменную меняется тот самый участок памяти. Мы можем изменять как бы оригинальную переменную, и даже присваивать ей новое значение

int someValue = 5;
add(ref someValue)
Console.WriteLine(someValue) // 6

void add(ref int i) => i++; 

out и in это ограниченные версии ref

out позволяет получить ссылку, однако не позволяет читать из неё внешнее значение. Таким образом out гарантирует, вы что должны передать ref из которого 100% сотрутся любые данные. По этой же причине out обязывает тебя присвоить ей что то (даже если это null). Out используется например в tryGetValue который позволяет одновременно проверить, имеется ли свойство, и получить значение

bool tryGetValue(int id, out object? x){
  if (data.Contains(id)) {
    x = data.get(id);
    return true;
  }

  // Главная цель затереть предыдущие данные из ref
  // Поэтому мы можем присвоить переменной значение null
  x = null; 
  return false;
}

in же в свою очередь предоставляет ref без возможности записи. Используется он очень редко, например у тебя имеется большая структура, или массив на стеке. Передавая его в метод он полностью копируется, чего мы можем избежать передавая только ССЫЛКУ на него. in гарантирует, что ссылка не будет изменена. Обычно она полезна при работе с динамическими библиотеками (т. к. обычно они возвращают указатели на структуры)

HugeData someData = new HugeData();

displayData(in someData); // someData не копируется

void displayData(in HugeData data) => ...

struct HugeData {
  // Много данных
} 
// btw структуры являются типами значений (как и int, short и т. п.)
// это значит что обычно они лежат на стеке
// и при передаче в виде аргумента копируются
// при этом изменяя их оригинал не меняется, как с объектами
→ Ссылка