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
var total = Sum(new IntSpanBuffer([1, 2, 3, 4, 5]));
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;
}
interface IReadOnlyIntBuffer
{
int Length { get; }
int this[int index] { get; }
}
ref struct IntSpanBuffer : IReadOnlyIntBuffer
{
private readonly ReadOnlySpan<int> values;
public IntSpanBuffer(ReadOnlySpan<int> values) => this.values = values;
public int Length => values.Length;
public int this[int index] => values[index];
}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;
}ref struct interfaces
The sample also relies on a companion C# 13 feature: ref struct types can now implement interfaces. Before C# 13, IntSpanBuffer could not declare : IReadOnlyIntBuffer at all.
- A
ref structcan never be converted to an interface type, because that would box it. Its interface members are used through a generic type parameter thatallows ref struct, asSumdoes - A
ref structmust implement every interface member, including members that have a default implementation
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 - See ref struct C# 7.2 for the type this constraint now allows as a generic type argument.