C# Span
last modified February 15, 2025
In this article, we show how to use the Span type in C#. The
Span type is a memory-efficient way to work with contiguous memory
regions, such as arrays, strings, and stack-allocated memory. It avoids
unnecessary memory allocations and improves performance.
The Span type is particularly useful for scenarios where you need
to manipulate slices of arrays or strings without creating additional copies.
The Span type is a ref struct that provides a type-safe and
memory-safe representation of a contiguous region of memory. It can point to
memory on the stack, heap, or even unmanaged memory. Unlike arrays,
Span does not allocate memory; it simply provides a view into
existing memory.
Creating a Span
The following example demonstrates how to create a Span from an array.
int[] numbers = { 1, 2, 3, 4, 5 };
// Create a Span from an array
Span<int> span = numbers.AsSpan();
// Modify the Span
span[0] = 10;
// Print the original array
Console.WriteLine(string.Join(", ", numbers));
In this program, a Span is created from an array using the
AsSpan method. Modifying the Span also modifies the
original array because Span provides a view into the array's
memory.
$ dotnet run 10, 2, 3, 4, 5
Slicing a Span
The following example demonstrates how to slice a Span to work with
a subset of its elements.
int[] numbers = { 1, 2, 3, 4, 5 };
// Create a Span from an array
Span<int> span = numbers.AsSpan();
// Slice the Span to get a subset
Span<int> slice = span.Slice(1, 3);
// Modify the slice
slice[0] = 20;
// Print the original array
Console.WriteLine(string.Join(", ", numbers));
In this program, the Slice method is used to create a
Span that represents a subset of the original array. Modifying the
slice also modifies the original array.
$ dotnet run 1, 20, 3, 4, 5
Span with Strings
The following example demonstrates how to use Span with strings to
avoid unnecessary allocations.
string text = "an old falcon"; // Create a Span from a string ReadOnlySpan<char> span = text.AsSpan(); // Slice the Span to get a substring ReadOnlySpan<char> slice = span.Slice(7, 6); // Print the slice Console.WriteLine(slice.ToString());
In this program, a ReadOnlySpan is created from a string using the
AsSpan method. The Slice method is used to extract a
substring without allocating additional memory.
$ dotnet run falcon
Stack Allocation with Span
The following example demonstrates how to use Span with
stack-allocated memory.
// Allocate memory on the stack
Span<int> span = stackalloc int[5] { 1, 2, 3, 4, 5 };
// Modify the Span
span[0] = 10;
Console.WriteLine(string.Join(", ", span.ToArray()));
In this program, the stackalloc keyword is used to allocate memory
on the stack, and a Span is created to work with this memory. This
avoids heap allocations and improves performance.
$ dotnet run 10, 2, 3, 4, 5
Comparing Efficiency of Span vs Array
The following example demonstrates the efficiency of Span compared
to a traditional array. We measure the time taken to sum elements in a large
array using both approaches.
using System.Diagnostics;
int dataSize = 100_000_000;
int[] dataArray = new int[dataSize];
Random random = new();
for (int i = 0; i < dataSize; i++)
{
dataArray[i] = random.Next(1, 100);
}
List<int> dataList = [.. dataArray];
void MeasureListSum()
{
Stopwatch stopwatch = Stopwatch.StartNew();
long sum = 0;
for (int i = 0; i < dataList.Count; i++)
{
sum += dataList[i];
}
stopwatch.Stop();
Console.WriteLine($"List Sum: {sum}, Time: {stopwatch.ElapsedMilliseconds} ms");
}
void MeasureSpanSum()
{
Stopwatch stopwatch = Stopwatch.StartNew();
long sum = 0;
Span<int> dataSpan = dataArray;
for (int i = 0; i < dataSpan.Length; i++)
{
sum += dataSpan[i];
}
stopwatch.Stop();
Console.WriteLine($"Span Sum: {sum}, Time: {stopwatch.ElapsedMilliseconds} ms");
}
MeasureListSum();
MeasureSpanSum();
In this program, we create a large array of 100 million integers and measure the
time taken to sum its elements using both a List and a
Span.
int dataSize = 100_000_000;
int[] dataArray = new int[dataSize];
Random random = new();
for (int i = 0; i < dataSize; i++)
{
dataArray[i] = random.Next(1, 100);
}
List<int> dataList = [.. dataArray];
An array of size 100_000_000 is created and filled with random integers. The
array is then used to initialize a List<int> .
Span<int> dataSpan = dataArray;
for (int i = 0; i < dataSpan.Length; i++)
{
sum += dataSpan[i];
}
Span<int> can offer performance benefits over
List<int> due to its lower overhead and ability to work
directly with slices of arrays without additional memory allocations.
$ dotnet run List Sum: 5000008283, Time: 524 ms Span Sum: 5000008283, Time: 412 ms
The results show that using Span is slightly faster than using a
traditional array, as it avoids unnecessary overhead and provides a more
efficient way to work with contiguous memory.
Source
In this article, we have shown how to use the Span type in C# for
memory-efficient operations. The Span type is a powerful tool for
working with contiguous memory regions without unnecessary allocations.
Author
List all C# tutorials.