Что-то меня смущает, и я надеюсь, что вы сможете прояснить ситуацию.
// This class assumes that T is definitively compatible to TheStruct
class ValueHolder<T> {
T _value;
TheStruct _structValue;
void Test1() {
_structValue = ref Unsafe<T, TheStruct>(ref _value); // ERROR: _structValue is not a by-ref value
// _structValue = Unsafe<T, TheStruct>(ref _value); // WORKS: Copy from stack to heap
}
void Test2() {
ref var structValue = ref _structValue;
structValue = ref Unsafe.As<T, TheStruct>(ref _value); // WORKS: Why, and what implication does it have?
}
}
Итак, мой вопрос в Test2: почему я могу назначить Unsafe.As в качестве ссылки при определении ref var structValue = ref _structValue;
. И что еще более важно, какие последствия это будет иметь, если использовать это поверх _structValue = Unsafe<T, TheStruct>(ref _value);
?
Спасибо за чтение, и я надеюсь, что вы сможете пролить свет на это. :)
ref var structValue = ref _structValue;
structValue = ref Unsafe.As<T, TheStruct>(ref _value); // WORKS: Why, and what implication does it have?
Почему я могу назначить Unsafe.As в качестве ссылки при определении ref var structValue = ссылка _structValue;
Потому что вы можете переназначить ссылку ref local
на другую ссылку.
Надеюсь, этот пример прояснит ситуацию:
var foo = 42;
var bar = 1;
ref var refVar = ref foo;
refVar++; // as if we wrote foo++
Console.WriteLine(foo); // 43
refVar = ref bar; // at this point we detach refVar as alias for foo
refVar++; // as if we wrote bar++
Console.WriteLine(foo); // still 43
Console.WriteLine(bar); // 2
Итак, к вашему первоначальному вопросу:
ref var structValue = ref _structValue;
structValue = ref Unsafe.As<T, TheStruct>(ref _value); // WORKS: Why, and what implication does it have?
вторая строка не будет присваивать полю _structvalue
ссылку, которая Unsafe.As
возвращает. Он присвоит ссылку на локальную переменную structValue
.
Поэтому, когда Test2
возвращается, вы фактически ничего не сделали с полем _structValue
. В рабочей части Test1
вы фактически скопировали значение, которое было там в данный момент, из _value
:
_structValue = Unsafe<T, TheStruct>(ref _value);
Будущие изменения _value
не будут отражены в _structValue
.
Возможно, вы захотите просмотреть ref-структуры, доступные в .NET 7, где вы можете иметь не только ref local
переменные, но и ref fields
такие как:
ref TheStruct _structValue;
Однако если бы вы сделали то, что хотели,
_structValue = ref Unsafe.As<T, TheStruct>(ref _value);
компилятор выдаст эту ошибку:
CS8374 Cannot ref-assign 'Unsafe.As<T, TheStruct>(ref _value)' to '_structValue' because 'Unsafe.As<T, TheStruct>(ref _value)' has a narrower escape scope than '_structValue'.
что мне кажется немного странным, потому что это поле в той же структуре... но это, возможно, другой вопрос.
Другой взгляд: когда Unsafe.As<,>
ref назначается ref var structValue = ref _structValue;
, не повредит ли это память по адресу _structValue
, когда Test2 вернется? Так что же я в конечном итоге назначаю _structvalue
? Тот же адрес _value
, на который я перешёл Unsafe.As<T, TheStruct>(ref _value)
?
@Teneko Я отредактировал свой ответ. во втором примере вы ничего не назначаете _structValue
. Вы назначаете локальную переменную ref structValue
.
Спасибо, теперь я понял. Последняя ошибка компилятора, о которой вы упомянули, была той ошибкой, которую я ожидал во втором примере. Ваш пример действительно был очень поучительным. Теперь я понимаю, что я просто заменяю адрес ссылки локальной ссылки, а не адрес ссылочного значения этой локальной ссылки.
Мне это также кажется несколько странным, но я думаю, что перегрузка Unsafe.As<,>
не знает, ограничено ли значение по ссылке локальным или полем, поэтому она всегда ограничивает возвращаемое значение ref локальным.
Я полностью осознаю это, что левая часть должна быть ref-переменной, если вы хотите присвоить ref-переменную, но вопрос в том, почему я могу это сделать:
structValue = ref Unsafe.As<T, TheStruct>(ref _value);
гдеstructValue
определяется какref var structValue = ref _structValue;
. Не перераспределяет лиUnsafe.As<,>
внутреннюю память и не приведет ли такое присвоение ссылки к нарушению допустимой области возвращаемого значения ссылкиUnsafe.As<,>
??