Почему нельзя вернуть результат возврата вложенной ссылки, если внутренний метод имеет другой параметр ref/out?

Я думал, что понял ограничения возвращает ref, а также экранирует области.

Но теперь я нашел дело, и я не понимаю, почему это незаконно. Кажется, что ref return нельзя использовать, если возвращаемое значение исходит от вложенного метода с какими-либо аргументами ref/out.

public static ref T RefReturn<T>()
{
    ref T result = ref GetResult<T>(normalParam: default); // compiles
    // ref T result = ref GetResult<T>(out bool outParam); // CS8157 at the return statement
    // ref T result = ref GetResult<T>(boxedParam: new StrongBox<bool>()); // a suboptimal workaround

    // ... code

    return ref result;
}

// the bodies below are just dummy examples
private static ref T GetResult<T>(bool normalParam) => ref (new T[1])[0];

// note that this method compiles in itself but unlike in case of the the previous method
// it is illegal to return its result again
private static ref T GetResult<T>(out bool outParam)
{
    outParam = true;
    return ref (new T[1])[0];
}

// though a ref/out parameter does not work we can mimic something similar without
// making it impossible to return its result from a caller
private static ref T GetResult<T>(StrongBox<bool> boxedParam)
{
    boxedParam.Value = true;
    return ref (new T[1])[0];
}

Я могу жить с обходным путем, но я не понимаю, как независимый аргумент по ссылке делает это решение вредным. Насколько я знаю, они не должны быть опасны для внутреннего результата рефери; в противном случае сам внутренний метод также должен вызвать некоторую ошибку. Или я ошибаюсь? Что мне не хватает?

Вот приведен живой пример приведенного выше кода.


person György Kőszeg    schedule 07.01.2021    source источник
comment
Обсуждается в этом вопросе (верхний комментарий должен был быть ответом). Параметр out bool — это не то же самое, что out bool локальный; компилятор может доказать безопасность использования первого, но не второго (точнее, он даже не будет пытаться).   -  person Jeroen Mostert    schedule 07.01.2021
comment
Прежде чем ответить на вопрос, полезно уточнить, в чем именно заключается ваше понимание этих вопросов. Рассмотрим этот более простой случай: static ref int M() { int x = 0; ref int y = ref N(ref x); return ref y;} static ref int N(ref int z) { return ref z; } (1) Вам ясно, почему это должно быть незаконным? Если нет, сначала проясните это в уме. (2) учитывая, что это должно быть незаконным, где, по вашему мнению, компилятор должен сообщить об ошибке и почему?   -  person Eric Lippert    schedule 07.01.2021
comment
@EricLippert: Ооо, думаю, теперь все ясно. И вы помогли мне понять, почему обходной путь в связанном посте работает (хотя мне он тоже не очень нравится): поднятие параметра out до того же уровня, что и возвращаемое значение ref, устраняет ошибку: ref T RefReturn<T>(out bool outParam). Создайте ответ, если хотите, и я приму его.   -  person György Kőszeg    schedule 07.01.2021
comment
@JeroenMostert: Спасибо за находку. Мне потребовалось некоторое время, чтобы понять как комментарий, так и то, почему опубликованное «исправление» работает, но Эрик дал мне последнюю часть недостающей информации.   -  person György Kőszeg    schedule 07.01.2021
comment
На самом деле эта функция была разработана и реализована в виде прототипа как минимум дважды (один раз мной) за много лет до того, как она вошла в поставляемую версию C#. Во время этого процесса проектирования мы перебрали множество возможных правил для определения того, когда такая ситуация может считаться безопасной; бывают случаи, когда компилятор может доказать, что возвращенная ссылка не может быть псевдонимом переданной ссылки. Должны ли мы подавить ошибку в этих случаях? Можем ли мы осчастливить верификатора в таких случаях? И не могли бы мы объяснить правила в спецификации?   -  person Eric Lippert    schedule 07.01.2021
comment
Дизайн — это процесс разрешения конфликтов, и здесь существует большой конфликт между тем, чтобы сделать правило простым, реализуемым и понятным, и тем, чтобы правило НЕ запрещало безопасные программы. В конце концов команда пришла к решению склоняться к тому, чтобы сделать ее простой, поэтому бывают случаи, когда вы знаете, что программа безопасна, и я знаю, что она безопасна, но ни компилятор, ни верификатор не знают об этом, и поэтому она запрещена. Это затем вызывает путаницу у пользователей. Это сложная проблема.   -  person Eric Lippert    schedule 07.01.2021
comment
В любом случае: рад, что вы разобрались, рад помочь!   -  person Eric Lippert    schedule 07.01.2021