Підрозділ 8.5
Змінні-посилання та повернення посилання
Розглядає ref local, повернення посилання з методу, зміну значення через посилання та обмеження для ref return.
8.5. Змінні-посилання та повернення посилання
Ми вже знаємо, що параметр із модифікатором ref дозволяє методу змінювати значення змінної, що знаходиться у викликаючому коді — бо передається не копія значення, а посилання на ділянку пам'яті. У C# ці можливості йдуть далі: можна визначити локальну змінну-посилання (ref local) і повертати посилання з методу (ref return). Це дозволяє маніпулювати значеннями в масивах і структурах безпосередньо в пам'яті, без копіювання.
Змінна-посилання (ref local)
Звичайне присвоєння double copy = x створює копію — нову ділянку пам'яті з тим самим значенням. Зміна copy не впливає на x. Якщо ж визначити змінну з ключовим словом ref, вона стане псевдонімом (alias) для вже існуючої ділянки пам'яті:
double pulse = 72.0;
ref double pulseRef = ref pulse; // pulseRef — псевдонім для pulseТепер pulseRef і pulse — це два імені для одного й того самого місця в пам'яті. Зміна одного одразу відображається в іншому.

Ref-змінну обов'язково потрібно ініціалізувати при оголошенні — визначити, на що вона вказує. Просте оголошення без ініціалізації не скомпілюється:
ref double r; // помилка — ref local без ініціалізаціїПобачимо поведінку на практиці:
Повернення посилання з методу (ref return)
Окрім локальних ref-змінних, C# дозволяє повернути посилання з методу. Це корисно, коли потрібно дати зовнішньому коду прямий доступ до елемента масиву або поля структури — без копіювання значення туди й назад.
Для цього в сигнатурі методу перед типом результату вказується ref, і після return також ставиться ref:
ref double Find(double target, double[] array)
{
for (int i = 0; i < array.Length; i++)
if (array[i] == target)
return ref array[i]; // повертаємо посилання на елемент
throw new IndexOutOfRangeException("значення не знайдено");
}Та при виклику змінна, що приймає результат, теж визначається з ref:
ref double element = ref Find(target, array);
element = newValue; // змінює безпосередньо елемент масивуЗастосуємо це в клінічному сценарії — знайдемо конкретний показник пульсу в журналі вимірювань і замінимо його виправленим значенням:
Зверніть увагу: метод FindReading повертає не значення 120.0, а посилання на комірку пам'яті arr[2]. Тому присвоєння wrong = 78.0 змінює саме цю комірку — елемент оригінального масиву readings.
ref return для двох значень
Ще один практичний приклад — метод, що повертає посилання на більше з двох значень. Це дозволяє безпосередньо змінити максимальний показник:
Параметри методу MaxRef також визначені з ref — бо метод повертає посилання на один із них, а посилання повинно вказувати на змінну, що існує поза межами методу.
ref readonly: посилання тільки для читання
Якщо потрібно дати доступ до елемента за посиланням (без копіювання), але захистити його від зміни, використовується ref readonly:
ref readonly double element = ref array[i]; // не можна змінити через element
// element = 99.0; // помилка компіляціїЦе зручно для read-only доступу до великих структур — ми уникаємо копіювання, але гарантуємо, що значення не зміниться через цю змінну.
Обмеження методів із ref return
Метод, що повертає посилання, підпорядковується певним правилам. Він не може повертати посилання на:
| Що заборонено | Причина |
|---|---|
null |
Посилання повинно вказувати на реальну ділянку пам'яті |
| Константу або літерал | Константи не мають адреси у купі |
Значення enum |
Аналогічно |
| Властивість класу або структури | Властивість не є змінною — це метод |
Поле з модифікатором readonly |
Захищено від змін |
| Локальну змінну всередині методу | Вона зникає після виходу з методу |
Повертати можна лише посилання на елементи масивів, поля екземпляра (без readonly) або параметри ref/out, — тобто на те, що існує поза межами поточного стекового кадру.