Something is confusing me, and I hope you can maybe clarify.
// 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?
}
}
So my question is in Test2: Why I can assign Unsafe.As as ref, when defining ref var structValue = ref _structValue;
. And more important, what does it have for implications, when using this over _structValue = Unsafe<T, TheStruct>(ref _value);
?
Thanks for reading and I hope you can bring some light into this. :)
ref var structValue = ref _structValue;
structValue = ref Unsafe.As<T, TheStruct>(ref _value); // WORKS: Why, and what implication does it have?
Why I can assign Unsafe.As as ref, when defining ref var structValue = ref _structValue;
Because you can reassign the reference of a ref local
to another reference.
This example will make things clear I hope:
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
So to your original question:
ref var structValue = ref _structValue;
structValue = ref Unsafe.As<T, TheStruct>(ref _value); // WORKS: Why, and what implication does it have?
the second line won't assign to the field _structvalue
the reference that Unsafe.As
returns. It will assign the reference to the local variable structValue
.
So when Test2
returns, you have actually done nothing to the field _structValue
. In Test1
for the working part you actually did copy the value which was there at the moment from _value
:
_structValue = Unsafe<T, TheStruct>(ref _value);
Future changes to _value
won't be reflected in _structValue
.
You may want to look in to ref structs available from .NET 7, where you can have not only ref local
variables, but ref fields
such as:
ref TheStruct _structValue;
If you did what you wanted, however,
_structValue = ref Unsafe.As<T, TheStruct>(ref _value);
the compiler will issue this error:
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'.
which I think is a bit strange, because it is a field in the same struct...but that's maybe another question.