When it comes to working with arrays and other collections of data in C#, developers often face challenges in terms of performance and memory management. In particular, copying or allocating additional memory can be a costly operation, especially for large arrays. To address these issues, C# 7.2 introduced the 'Span<T>' type, which provides a way to work with arrays and memory in a more efficient and performant manner.
What is Span<T>?
'Span<T>' is a type in C# that was introduced in version 7.2 of the language. The 'Span<T>' type is defined in the 'System' namespace and is typically used for efficient manipulation of arrays and other collections of data. It represents a contiguous sequence of elements of type T stored in memory. In other words, 'Span<T>' provides a way to view and manipulate data stored in memory as a sequence of values of a specific type.
One of the key features of 'Span<T>' is that it provides a view of memory, rather than a copy of it. This means that 'Span<T>' instances do not allocate any additional memory on the heap. Instead, they refer to existing memory, such as an array or a block of unmanaged memory.
'Span<T>' provides a number of useful methods for working with arrays and other collections of data, including indexing, slicing, and conversion to and from other types. These methods make it easy to work with 'Span<T>' instances in a way that is similar to working with arrays.
Benefits of using Span<T>
One of the primary benefits of using 'Span<T>' is improved performance. By avoiding the need to copy or allocate additional memory, Span<T>' can provide significant performance improvements, especially for large arrays or collections of data. Additionally, Span<T>' can be used for interoperability with unmanaged memory and for working with external APIs that expect contiguous blocks of memory. There many other benefits are as below:
- Improved performance: 'Span<T>' can help improve the performance of array and memory manipulation operations by avoiding the need to copy or allocate additional memory.
- Memory safety: 'Span<T>' provides a type-safe and bounds-checked way to access memory, helping to prevent common memory-related errors such as buffer overflows and null reference exceptions.
- Interoperability: 'Span<T>' can be used for working with unmanaged memory and for interoperability with external APIs that expect contiguous blocks of memory.
- Lower memory usage: By avoiding the need to copy or allocate additional memory, 'Span<T>' can help reduce the memory usage of applications that work with large arrays or collections of data.
- Simplified code: 'Span<T>' provides a simple and consistent way to work with arrays and memory, reducing the amount of boilerplate code required for common operations.
- Parallelism: 'Span<T>' can be used to efficiently work with data in parallel, thanks to its efficient memory access and type-safe operations.
- Reduced GC pressure: By reducing the amount of memory allocation and copying, Span<T> can help reduce the pressure on the garbage collector, leading to better performance and reduced memory fragmentation.
Let's see the example that demonstrates how Span<T> can be more useful than arrays for array manipulation:
public class SpanVsArray
{
private const int arraySize = 1000000;
private readonly int[] array = new int[arraySize];
private readonly byte[] memory = new byte[arraySize * sizeof(int)];
public SpanVsArray()
{
var rand = new Random();
for (int i = 0; i < arraySize; i++)
{
int value = rand.Next();
array[i] = value;
MemoryMarshal.Write(memory.AsSpan(i * sizeof(int)), ref value);
}
}
[Benchmark]
public long ArraySum()
{
long sum = 0;
for (int i = 0; i < arraySize; i++)
{
sum += array[i];
}
return sum;
}
[Benchmark]
public long SpanSum()
{
Span<byte> spanMemory = memory.AsSpan();
long sum = 0;
var span = MemoryMarshal.Cast<byte, int>(spanMemory);
for (int i = 0; i < arraySize; i++)
{
sum += span[i];
}
return sum;
}
}

Join the conversation! Your thoughts help the community grow.