| Async Streams in C# :👈 | 👉:C#/.NET Core Coding Guidelines |
📏 Span<T> in C# |
Span<T> in C#
Span<T> is a value type in C# that represents a contiguous block of memory. It provides a safe, low-overhead way to work with sections of memory from various sources without allocating new memory on the heap. This makes it a powerful tool for writing high-performance, low-allocation code.
What Span<T> is
Think of Span<T> as a "view" or "slice" into a block of memory. The memory it points to can come from:
- An array or a section of an array.
- A string (using the immutable
ReadOnlySpan<char>). - Stack-allocated memory (using the
stackallockeyword). - Unmanaged or native memory.
Key characteristics of Span<T>
- Zero heap allocation: Unlike creating a Substring or Subarray, which makes a new copy on the managed heap, a
Span<T>is allocated on the stack. This eliminates overhead and reduces garbage collection pressure. - Performance: Because it is a
ref structthat holds a direct reference and a length, indexing aSpan<T>is as fast as indexing a raw array. - Memory safety: The C# compiler enforces strict rules to prevent
Span<T>from being used in ways that could lead to memory corruption, such as escaping the stack. - Slicing: The
Slice()method allows you to easily create a newSpan<T>that refers to a subset of the original memory, all without any additional memory allocation.
Example
int[] numbers = { 10, 20, 30, 40, 50 };
Span<int> slice = numbers.AsSpan(1, 3); // Refers to elements [20, 30, 40]
foreach (var num in slice)
{
Console.WriteLine(num);
}
Version Introduced
Span<T> was introduced in C# 7.2 and supported by the .NET Core 2.1 runtime.
A version was also backported for use with older .NET versions via a NuGet package, but the deepest optimizations were included in .NET Core.
Limitations and Alternatives
Due to its stack-only nature, Span<T> comes with a few limitations:
- It cannot be used as a field in a class.
- It cannot be used inside
asyncmethods, iterator blocks, or acrossawaitandyieldboundaries. - It cannot be boxed or used as a generic type argument.
For asynchronous operations or scenarios where the memory needs to live on the heap, use its companion type Memory<T>.
Memory<T> can be stored on the heap and safely passed across async boundaries.
When you need to perform high-performance, synchronous work on it, you can access its Span property.
Example Using Memory<T>
Memory<int> memory = new int[] { 1, 2, 3, 4, 5 };
Span<int> span = memory.Span;
span[0] = 99;
Console.WriteLine(memory.Span[0]); // Output: 99
Summary
- Span<T> is best for high-performance, stack-based, synchronous operations.
- Use Memory<T> when you need heap allocation or async compatibility.
- They both improve performance by reducing memory allocations and enabling safe access to memory.
📏 Span<T> in C#
Span<T> is a stack-only, memory-safe type introduced in C# 7.2 that provides a view over contiguous memory. It allows slicing and manipulation of arrays, strings, or unmanaged memory without additional allocations.
💡 Example: Using Span<T>
using System;
class Program {
static void Main() {
int[] numbers = { 1, 2, 3, 4, 5, 6 };
Span<int> span = numbers;
// Slice the span
Span<int> middle = span.Slice(2, 3); // {3, 4, 5}
// Modify the slice
for (int i = 0; i < middle.Length; i++) {
middle[i] *= 10;
}
// Output original array to show changes
foreach (var num in numbers) {
Console.WriteLine(num);
}
}
}
✅ Best Practices
- Use Span<T> for short-lived, high-performance operations.
- Prefer
ReadOnlySpan<T>when you don’t need to modify data. - Use
stackallocfor temporary buffers on the stack. - Avoid returning
Span<T>from methods—it's stack-bound. - Use
Memory<T>for async or heap-based scenarios.
📌 When to Use
- For performance-critical code that avoids heap allocations.
- When working with slices of arrays or buffers.
- In parsing routines (e.g., string manipulation).
- For interop scenarios with unmanaged memory.
🚫 When Not to Use
- In async methods—use
Memory<T>instead. - For long-lived data—Span is stack-bound and short-lived.
- In class fields—Span cannot be stored in heap objects.
⚠️ Precautions
- Don’t escape Span outside its stack scope.
- Be cautious with unsafe code when using Span over unmanaged memory.
- Ensure bounds safety when slicing or indexing.
- Use ReadOnlySpan to prevent accidental mutations.
🎯 Advantages
- Zero allocations: No heap usage for slicing and manipulation.
- Memory safety: Bounds-checked and type-safe.
- Performance: Ideal for high-throughput scenarios.
- Versatility: Works with arrays, strings, stackalloc, and unmanaged memory.
- Cleaner code: Reduces need for temporary arrays or buffers.
📝 Conclusion
Span<T> is a powerful tool for efficient memory access in C#. It’s best suited for performance-sensitive, short-lived operations where safety and speed matter. Use it wisely to write faster and cleaner code.
| Async Streams in C# :👈 | 👉:C#/.NET Core Coding Guidelines |