If you have ever worked with strings, or arrays in C#, you have probably seen code that copies data more times than needed.

Extra copying increases memory usage and hurts performance. Modern applications handle large data streams, buffers, network packets, and processing pipelines, so controlling allocations matters.

Spans, gives you a safe view over existing memory without allocating new memory.

What Is Span<T>?

Span, is a value type that enables the representation of contiguous regions of arbitrary memory.

A Simple Example

Without Span<T> (Traditional Approach)

If you wanted elements 3, 4, 5 from the array before Span existed, you would usually write:

int[] numbers = { 1, 2, 3, 4, 5, 6 };

// We want { 3, 4, 5 }
int[] slice = new int[3];

for (int i = 0; i < 3; i++)
    slice[i] = numbers[i + 2];

foreach (var x in slice)
    Console.WriteLine(x);

What happens here?

This is called allocation, and allocations in .NET always go to the managed heap, which:

With Span<T> (Zero Allocation Approach)

int[] numbers = { 1, 2, 3, 4, 5, 6 };

// Create a span over the array
Span<int> span = numbers;

// Slice the span (no copying)
Span<int> slice = span.Slice(2, 3);

foreach (var x in slice)
    Console.WriteLine(x);

What happens now?

But be careful, any changes made to Span slice it will be also made in created array since we are pointing to it in the first place.

Visually

slice is simply a window over the existing data.

Working With Strings Using ReadOnlySpan<char>

Strings are immutable. If you split or substring, you usually create new strings.

Example

string text = "HelloWorld";
string part = text.Substring(5); // Allocates a new string

Using spans

ReadOnlySpan<char> span = text;
ReadOnlySpan<char> partSpan = span.Slice(5);

No allocation. Very helpful when parsing large text.

Real Use Case: Parsing Numbers

string input = "12345";
ReadOnlySpan<char> span = input;

int result = int.Parse(span); // Works directly with ReadOnlySpan
Console.WriteLine(result); // 12345

No intermediate string allocations.

Important Constraint: Span<T> Is Stack Only

You cannot do this:

class Test
{
    private Span<int> field; // Not allowed
}

Because Span may refer to stack memory which would be unsafe if stored beyond the current scope. This is a deliberate safety guarantee.

If you need something similar that can live on the heap, use Memory<T> or ReadOnlyMemory<T>.