Можно ли передать значимый тип (value type) по ссылке в C#?

Ответ

Да, в C# значимые типы (struct, int, bool и т.д.) можно передавать по ссылке, избегая копирования. Для этого используются модификаторы ref, out и in.

1. ref (передача по ссылке с возможностью чтения и записи): Переменная должна быть инициализирована до передачи.

void DoubleValue(ref int number) {
    number *= 2; // Модифицирует оригинальную переменную
}

int value = 5;
DoubleValue(ref value);
Console.WriteLine(value); // Вывод: 10

2. out (передача по ссылке только для записи результата): Метод обязан присвоить значение out-параметру. Переменная может быть неинициализированной.

bool TryDivide(int dividend, int divisor, out int result) {
    if (divisor != 0) {
        result = dividend / divisor; // Обязательное присваивание
        return true;
    }
    result = 0; // Присваивание даже в случае ошибки
    return false;
}

if (TryDivide(10, 2, out int quotient)) {
    Console.WriteLine(quotient); // Вывод: 5
}

3. in (C# 7.2+, передача по ссылке только для чтения): Гарантирует, что метод не изменит передаваемое значение. Полезно для больших структур.

readonly struct LargeStruct { public double X, Y, Z; }

double CalculateDistance(in LargeStruct point) {
    // point.X = 10; // Ошибка компиляции: нельзя модифицировать
    return Math.Sqrt(point.X * point.X + point.Y * point.Y + point.Z * point.Z);
}
Ключевые отличия: Модификатор Инициализация до вызова Обязанность присвоения в методе Возможность чтения в методе Возможность записи в методе
ref Да Нет Да Да
out Нет Да Нет (до присваивания) Да
in Да Нет Да Нет

Ответ 18+ 🔞

А, ну ты про эти твои структуры, которые как кирпичи — тащить их туда-сюда, так всю спину сорвёшь, блядь. Да, в C# эту поебень можно не копировать, а передавать по ссылке, чтобы не ебаться с лишними операциями. Смотри, как это делается.

Вот есть три модификатора, как три богатыря, только с разными приколами: ref, out и in.

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

void УдвоитьЗначение(ref int число) {
    число *= 2; // Меняет оригинал нахуй
}

int значение = 5;
УдвоитьЗначение(ref значение);
Console.WriteLine(значение); // Будет 10, ебать

2. out — это как отправить этого же друга в магазин за водкой. Ему даёшь пустую бутылку (переменную), и он ОБЯЗАН вернуться с полной. Не может прийти и сказать «ой, забыл». В методе ты ДОЛЖЕН этой переменной что-то присвоить, иначе компилятор тебе ебло набьёт.

bool ПопробоватьПоделить(int делимое, int делитель, out int результат) {
    if (делитель != 0) {
        результат = делимое / делитель; // Вот, присваиваешь, молодец
        return true;
    }
    результат = 0; // Даже если пиздец, всё равно надо присвоить!
    return false;
}

if (ПопробоватьПоделить(10, 2, out int частное)) {
    Console.WriteLine(частное); // Выведет 5, красота
}

3. in — это как показать другу свою коллекцию марок, но в перчатках и под присмотром. Смотреть можно, трогать можно, но оторвать уголок или нахуярить на марке усы — низя. Добавили в C# 7.2, чтоб большие структуры не копировать, но и не давать их менять.

readonly struct БольшаяСтруктура { public double X, Y, Z; }

double ВычислитьРасстояние(in БольшаяСтруктура точка) {
    // точка.X = 10; // Ошибка компиляции, сука! Руки прочь!
    return Math.Sqrt(точка.X * точка.X + точка.Y * точка.Y + точка.Z * точка.Z);
}

А вот тебе табличка, чтоб совсем пиздец понятно стало:

Модификатор Нужно инициализировать до вызова? Метод ОБЯЗАН присвоить значение? Можно читать в методе? Можно писать в методе?
ref Да, блядь Нет Да Да, на здоровье
out Не, похуй Да, обязательно! Нет (пока не присвоил) Да
in Да Нет Да Ни в коем случае, нахуй

Вот и вся магия. Выбирай, что тебе нужно: дать поменять, заставить вернуть результат или просто безопасно показать данные. Главное — не перепутай, а то получишь либо ошибку компиляции, либо неожиданный пиздец в рантайме.