Ответ 1
Я думаю, что это описано в разделе ref-readonly, Safe To Return Rules.
"это" небезопасно возвращать из членов структуры
Это ты уже знаешь. Вы можете прочитать больше о том, почему он не имеет права здесь. Короче говоря, это позволяет "загрязнять любой метод ref-return, вызванный локальным типом значения", поэтому включение всех возвратов ref из методов в структурах не "безопасно для возврата", потому что они могут потенциально содержать ref для этого.
ref/in параметры безопасны для возврата
поля структуры экземпляра безопасны для возврата, если приемник безопасен для возврата
Это охватывает случай статического метода. Параметр foo
безопасен для возврата (потому что in
), и, следовательно, foo._x
безопасно возвращать, будучи полем экземпляра структуры, который сам по себе безопасен для возврата.
ref, возвращенный из другого метода, безопасно возвращать, если все refs/outs переданы этому методу, так как формальные параметры были бы безопасны для возврата.
Это предотвращает проблемы с указанным выше статическим методом. Это делает следующие недопустимые:
public static ref readonly int ExtensionGetX(in Foo foo) {
return ref foo._x;
}
static ref readonly int Test() {
var s = new Foo();
s._x = 2;
// fails to compile
return ref ExtensionGetX(s);
}
Поскольку s
небезопасно возвращаться, ref, полученный нами из ExtensionGetX
небезопасно возвращать, поэтому мы не можем течь указатель на локальную переменную за пределами области видимости.
Короче говоря, это разрешено, потому что оно безопасно и не имеет определенного недостатка, который запрещает возвращать ref к "этому" из метода struct member.
Обновить. Я не думаю, что обновление вашего вопроса меняет мой ответ. Правила "безопасного возвращения", упомянутые выше, остаются неизменными. Вы изменили in
к ref
, но ref
параметр также безопасен для возврата. Так что это поле экземпляра. Но если вы возвращаете параметр небезопасным:
public static ref int GetXRef(Foo foo)
{
return ref foo._x;
}
Тогда он не будет компилироваться.
Вы также думаете (в комментарии), что "вы не можете сохранить возвращаемую ссылку как локальную переменную", но это не так:
ref int y = ref FooExtensions.GetXRef(ref f);
y = 10;
// print 10
Console.WriteLine(f.X);
Таким образом, readonly или нет, in
или ref
safe для возврата правил гарантируют, что он безопасно будет возвращать член ref struct в этой ситуации, позволяя возвращать ссылку на this
из struct local method имеет нежелательные последствия, заставляя обрабатывать все значения ref, возвращаемые всеми как небезопасные для возврата.
Небольшой пример того, что не было бы возможным, если член структуры может вернуть реф в this
:
public ref int GetXRefMember(ref int y) => ref y;
static ref int Test(ref int y) {
var x = new Foo();
// safe to return, but won't be if ref to 'this' can
// ever be returned from struct local method
return ref x.GetXRefMember(ref y);
}