Hasty Briefsbeta

Bilingual

Span-First C#: Designing Around Span<T>

9 hours ago
  • Span<T> is a ref struct that provides a type-safe, bounds-checked view over contiguous memory without owning or copying the memory.
  • It can wrap arrays, strings, stackalloc blocks, and unmanaged memory via MemoryMarshal.
  • Span<T> is stack-only, preventing heap allocation and ensuring safety from GC relocation.
  • Four related types (Span<T>, ReadOnlySpan<T>, Memory<T>, ReadOnlyMemory<T>) cover mutable/read-only and stack/heap axes.
  • Memory<T> is the heap-storable counterpart for async scenarios, while Span<T> is for synchronous use.
  • ref struct restriction by Span<T> enforces lifetime management at compile time, disallowing field storage, boxing, async await, and closures.
  • C# 13 allows ref struct as generic type parameter constraint, but does not lift field, closure, or async restrictions.
  • Slicing produces a new Span<T> over a subrange without copying, using index and range syntax.
  • stackalloc with Span<T> provides stack-allocated buffers with no GC pressure, but is limited to the current stack frame and usually under 1-2 KB.
  • Span-first parsing avoids allocations by walking indices over the original buffer and only materializing strings or numbers at final consumption.
  • SearchValues<T> (NET 8+) optimizes repeated IndexOfAny calls for tokenizers and delimiter scanning.
  • Span-first API design uses ReadOnlySpan<T> as the canonical overload, with array/string overloads as thin convenience wrappers.
  • MemoryMarshal allows reinterpreting spans across type boundaries, e.g., casting byte buffers to struct spans without copying.
  • Common failure mode: using Span<T> with async methods; fix by using Memory<T> at async layer and Span<T> at synchronous leaf.
  • Span-first parsing shows significant performance and memory benefits over string-based parsing, with zero allocations and lower latency.
  • Safety caveats include compiler catching direct escapes of stackalloc spans but not all indirect ones, and slice bounds checks being cheap but not free.
  • Dictionary keyed by strings cannot use ReadOnlySpan<char> directly without ToString(), but NET 9 offers GetAlternateLookup for span-keyed lookup.
  • Span<T> lacks IEnumerable<T> implementation, so LINQ methods are unavailable and must be hand-rolled.