ref struct types were introduced in C# 7.2 but could not contain ref fields. This meant low-level types like Span<T> had to be implemented with internal runtime magic rather than expressible C#.
C# 11 allows ref fields inside ref struct types and introduces the scoped modifier to control the lifetime of ref values, preventing them from escaping to a wider scope than intended.
Code
C#
ref struct RefArray
{
ref int first;
int length;
public RefArray(ref int first, int length)
{
this.first = ref first;
this.length = length;
}
public ref int this[int index] => ref Unsafe.Add(ref first, index);
}
// scoped prevents a ref parameter from escaping the method
void Process(scoped ref int value)
{
// Cannot assign 'value' to a field or return it
}C#
ref struct RefArray
{
// ref fields were not allowed - had to use pointers or internal tricks
unsafe int* first;
int length;
public unsafe RefArray(int* first, int length)
{
this.first = first;
this.length = length;
}
public unsafe ref int this[int index] => ref *(first + index);
}Notes
reffields can only be declared insideref structtypes- The
scopedmodifier can be applied torefparameters and locals to restrict their lifetime to the current method Span<T>andReadOnlySpan<T>are now definable in pure C# using this feature- The
refof areffield can be reassigned using= ref