Чем параметр in отличается от ref и out? Зачем передавать большую struct через in вместо копирования по значению?

C# / .NET Основы языка Junior

Что это: Параметр in передаёт readonly-ссылку на аргумент: метод читает значение без копирования, но не может его изменить. ref позволяет читать и писать, out требует присвоения внутри метода. in удобен для крупных struct, где копирование по значению дорого.

Почему важно: Это базовая тема передачи параметров: понимание in показывает, что C# оптимизирует struct не только через стек, но и через readonly-ссылки без boxing.

Под капотом: Компилятор генерирует managed pointer с атрибутом IsReadOnly в IL. JIT передаёт адрес struct, а попытка записи блокируется на этапе компиляции (CS8331). Для мелких struct компилятор может всё равно передать по значению как оптимизацию.

Типичная ошибка: Разработчики помечают маленькие struct параметром in «для скорости» и усложняют сигнатуру, хотя для int или Point копирование дешевле, а readonly ref иногда мешает оптимизациям регистров.

struct Matrix4x4 { public float M11; /* ... 15 полей */ }

void Transform(in Matrix4x4 matrix)
{
    // matrix = default; // CS8331: нельзя присвоить in-параметру
    Use(matrix.M11);
}

Matrix4x4 m = default;
Transform(in m); // передаётся ссылка, без копирования 64 байт