Обязательна ли модификация out параметра внутри функции в C#
Что проверяют
Знаете ли вы правила определённого присваивания в C# и чем out отличается от ref и in. Вопрос простой, но кандидат, ответивший «не обязательна», сразу показывает, что с out на практике дела не имел.
Как отвечать
Да, обязательна. Компилятор требует, чтобы каждому out параметру было присвоено значение на всех путях, ведущих к нормальному выходу из метода. Иначе это ошибка компиляции, а не предупреждение. Внутри метода out параметр считается неприсвоенным: прочитать его до первой записи нельзя, даже если вызывающий код что-то в переменную положил.
Разница с соседями:
ref: переменная инициализируется вызывающим, метод вправе её вообще не трогать;out: инициализация у вызывающего не нужна, а запись внутри обязательна;in: передача по ссылке только для чтения, записывать нельзя.
Детали, которые показывают опыт:
- путь, завершающийся через
throw, присваивания не требует, правило проверяется только там, где управление возвращается; - при нескольких точках выхода проще сразу написать
value = default;, чем ловитьCS0177в редкой ветке; outнельзя применять в асинхронных методах и итераторах и нельзя захватывать в лямбду;- типичное применение это паттерн
Try, где приfalseв параметр кладётся значение по умолчанию.
static bool TryFind(string key, out string value)
{
value = string.Empty; // без этого ветка с return false не соберётся
if (!store.TryGetValue(key, out var found)) return false;
value = found;
return true;
}Где спотыкаются
Считают, что достаточно присвоить в удачной ветке. Компилятор смотрит все пути, и ранний return false без записи ломает сборку.
Второе: меняют местами правила и уверенно заявляют, что это ref обязан быть изменён. ref не обязан ничего, обязанность лежит на out.
Третье: называют out передачей копии и добавляют, что так возвращать несколько значений быстрее, чем кортежем. Передаётся ссылка, а выбор между out и кортежем это вопрос читаемости, а не скорости.