Generic type parameters could not accept ref struct types like Span<T> or ReadOnlySpan<T>. This meant high-performance code using spans could not participate in generic abstractions that preserved stack-only lifetime rules.
C# 13 introduces the allows ref struct anti-constraint, enabling generic type parameters to accept ref struct types while the compiler enforces the necessary lifetime restrictions.
Code
csharp
interface IReadOnlyIntBuffer
{
int Length { get; }
int this[int index] { get; }
}
ref struct IntSpanBuffer(ReadOnlySpan<int> values) : IReadOnlyIntBuffer
{
public int Length => values.Length;
public int this[int index] => values[index];
}
static int Sum<TBuffer>(scoped TBuffer buffer)
where TBuffer : IReadOnlyIntBuffer, allows ref struct
{
var result = 0;
for (var i = 0; i < buffer.Length; i++)
result += buffer[i];
return result;
}
var total = Sum(new IntSpanBuffer([1, 2, 3, 4, 5]));csharp
// Could not use a ref struct as a generic type argument.
// You had to write overloads for each stack-only buffer shape.
static int Sum(ReadOnlySpan<int> values)
{
var result = 0;
foreach (var value in values)
result += value;
return result;
}Notes
allows ref structis an anti-constraint that relaxes the default restriction rather than adding one- The compiler ensures
ref structvalues are not used in ways that would violate their lifetime rules (e.g. boxing, storing in fields of non-ref structtypes) - Enables the BCL to offer
Span<T>-based overloads in generic APIs