A partir de C# 7.2 y .NET Core 2.1, Microsoft introdujo una de las herramientas más poderosas para manipular memoria sin sacrificar seguridad: Span<T>. Esta estructura permite trabajar con porciones contiguas de memoria (arrays, segmentos de strings, buffers, etc.) de forma eficiente, sin generar asignaciones en el heap ni usar punteros directamente.
Span<T> es una estructura stack-only que representa una ventana mutable sobre un bloque contiguo de memoria. Podés usarlo para acceder, cortar o modificar datos de arrays, slices de strings, buffers nativos, y más, sin necesidad de copiar datos.
Veamos un ejemplo:
int[] numbers = { 1, 2, 3, 4, 5 };
Span<int> slice = numbers.AsSpan(1, 3); // Contiene 2, 3, 4
slice[0] = 42;
Console.WriteLine(numbers[1]); // Muestra 42 (modificó el array original)
¿Por qué usar Span<T>?
- Evita copias de memoria innecesarias
- No genera asignaciones en el heap
- Mejora la performance en procesamiento de strings, buffers y arrays
- Ofrece seguridad de tipos y bounds-checking
- Solo puede usarse dentro del stack (no puede almacenarse en campos de clase)
Limitaciones:
- No puede usarse en métodos async o iteradores (async, yield return)
- No puede almacenarse en campos de clase o como parte de objetos del heap
- Si necesitás algo similar pero heap-safe, podés usar Memory<T>
Veamos un ejemplo de string:
ReadOnlySpan<char> span = "Hola Mundo".AsSpan(5);
Console.WriteLine(span.ToString()); // Mundo
Esto es ideal para parsear strings sin crear substrings intermedias.
Span<T> es una herramienta fundamental si querés escribir código de alto rendimiento en .NET. Es ideal para manipular datos binarios, strings o buffers, con el mínimo impacto en el garbage collector. Aunque tiene limitaciones (no se puede escapar del stack), su potencia compensa con creces en escenarios críticos de performance.