allows ref struct
🥷 Ninjakod-varning
Det här är avancerad teknik för prestanda-kritisk kod. Du behöver förstå
Span<T>,ref structoch generiska constraints innan detta ger mening. För daglig YH-kod behöver du inte detta — men du kan stöta på det i open source och bibliotekskod.
allows ref struct är en anti-constraint som talar om för kompilatorn att en generisk typparameter får vara en ref struct — till exempel Span<T> eller ReadOnlySpan<T>.
Bakgrund — vad är ref struct?
En ref struct är en struct som alltid lever på stacken — den får aldrig allokeras på heapen, boxas eller sparas i ett fält. Det gör den extremt snabb men ger strikta begränsningar.
Span<T> och ReadOnlySpan<T> är de vanligaste ref struct-typerna. De representerar ett sammanhängande minnesblock utan kopiering:
// ReadOnlySpan — refererar till befintligt minne, ingen allokeringstring text = "hej världen";ReadOnlySpan<char> slice = text.AsSpan(4, 6); // "värld" — nollkopieringProblemet utan allows ref struct
Generiska metoder kan normalt inte ta emot ref struct:
// Kompileringsfel — T kan inte vara en ref structvoid Process<T>(T value) where T : struct{ // ...}
Process(new Span<int>(new int[5])); // errorAnledningen: kompilatorn garanterar att T kan placeras var som helst — i fält, på heapen, i en lista. Men ref struct får inte det. Utan extra information kan kompilatorn inte tillåta det.
Lösningen — allows ref struct
// T får nu vara en ref structvoid Process<T>(T value) where T : allows ref struct{ // ...}
Process(new Span<int>(new int[5])); // OK!allows ref struct säger: “den här typparametern får vara en ref struct, men behöver inte vara det.”
Praktiskt exempel — nollkopierings-parser
// Generisk metod som arbetar med Span<T> utan att kopiera dataint CountOccurrences<T>(ReadOnlySpan<T> source, T target) where T : IEquatable<T>, allows ref struct{ int count = 0; for (int i = 0; i < source.Length; i++) if (source[i].Equals(target)) count++; return count;}string text = "banana";ReadOnlySpan<char> span = text.AsSpan();
Console.WriteLine(CountOccurrences(span, 'a')); // 3Utan allows ref struct skulle CountOccurrences inte acceptera en ReadOnlySpan<char> — och du hade behövt kopiera strängen till en array.
Interface och ref struct (C# 13)
ref struct kan nu implementera interface, men med begränsningen att de aldrig boxas:
interface IBuffer<T>{ int Length { get; } T this[int index] { get; }}
ref struct FastBuffer<T> : IBuffer<T>{ private readonly Span<T> _data;
public FastBuffer(Span<T> data) => _data = data;
public int Length => _data.Length; public T this[int i] => _data[i];}int[] data = [10, 20, 30, 40, 50];var buffer = new FastBuffer<int>(data);
Console.WriteLine(buffer.Length); // 5Console.WriteLine(buffer[2]); // 30När är detta relevant?
- Du skriver ett bibliotek eller en parser som ska hantera stora datamängder utan heap-allokeringar
- Du arbetar med binärprotokoll, textparsning eller nätverksbuffertar
- Du optimerar en “hot path” som kallas miljoner gånger per sekund
För normal applikationskod — API:er, databaser, webbtjänster — behöver du aldrig tänka på detta.
TL;DR
// Utan allows ref struct — T kan inte vara Span<T>void Old<T>(T value) where T : struct { }
// Med allows ref struct — T kan vara Span<T>, ReadOnlySpan<T> osv.void New<T>(T value) where T : allows ref struct { }allows ref struct öppnar dörren för generisk, nollkopierings-kod med Span<T>. Det är ett biblioteksverktyg — inte vardagskod.