Skip to content

allows ref struct C# 13.0performancenew scenarios

Allow ref struct types to be used as generic type arguments.

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 struct can never be converted to an interface type, because that would box it. Its interface members are used through a generic type parameter that allows ref struct, as Sum does
  • A ref struct must implement every interface member, including members that have a default implementation

Notes ​

  • allows ref struct is an anti-constraint that relaxes the default restriction rather than adding one
  • The compiler ensures ref struct values are not used in ways that would violate their lifetime rules (e.g. boxing, storing in fields of non-ref struct types)
  • 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.

More information ​

Powered by Intracia