C#
Memory and Span
Write high-performance operations with Span<T> and unsafe code.
Memory and Span
Span<T> opens a zero-copy window over a memory region. With ReadOnlySpan<char> you can process a substring of a string without Split or Substring; this avoids allocation.
In this lesson we add a ParseWithSpan method: it extracts the level name from a log line up to the first : using IndexOf and Slice. We also show pointer use with an unsafe method.
Pointers with unsafe
An unsafe block enables low-level memory access through pointers. int* pa = &a; takes the address of a local variable; *pa reads its value. This is useful in performance-critical numeric work.
In this lesson the UnsafeSum method will add two ints via pointers. In real projects unsafe is used carefully because memory safety guarantees are lifted.
Exercise Add ParseWithSpan and UnsafeSum
Add two methods to LogProcessor. public static string ParseWithSpan(ReadOnlySpan<char> log): find ':' with int colon = log.IndexOf(':');, return empty if colon < 0, else log.Slice(0, colon).ToString(). public static unsafe int UnsafeSum(int a, int b): int* pa = &a; int* pb = &b; return *pa + *pb;. In Main, call Console.WriteLine(LogProcessor.ParseWithSpan("ERROR: disk".AsSpan())) and Console.WriteLine(LogProcessor.UnsafeSum(3, 4)).
Show example solution
Console.WriteLine(LogProcessor.ParseWithSpan("ERROR: disk".AsSpan())); and Console.WriteLine(LogProcessor.UnsafeSum(3, 4));
Example solution:
using System;
static class LogProcessor
{
public static int ParseLevel(string level)
{
return level switch
{
"INFO" => 0,
"WARN" => 1,
"ERROR" => 2,
_ => -1
};
}
public static int CountByLevel(string[] logs, int targetLevel)
{
int count = 0;
foreach (var log in logs)
{
if (ParseLevel(log.Split(':')[0]) == targetLevel)
{
count++;
}
}
return count;
}
public static string ParseWithSpan(ReadOnlySpan<char> log)
{
int colon = log.IndexOf(':');
if (colon < 0) return "";
return log.Slice(0, colon).ToString();
}
public static unsafe int UnsafeSum(int a, int b)
{
int* pa = &a;
int* pb = &b;
return *pa + *pb;
}
}
class Program
{
static void Main()
{
Console.WriteLine("LogProcessor skeleton ready");
var logs = new[] { "INFO: a", "WARN: b", "INFO: c", "ERROR: d" };
Console.WriteLine(LogProcessor.CountByLevel(logs, 0));
Console.WriteLine(LogProcessor.ParseWithSpan("ERROR: disk".AsSpan()));
Console.WriteLine(LogProcessor.UnsafeSum(3, 4));
}
}
Test yourself
-
Complete the ReadOnlySpan declaration
ReadOnlySpan<____> log
Show answer
ReadOnlySpan<char> log
-
Which symbol declares a pointer in C#?
- & (address)
- * (pointer)
- -> (member access)
- sizeof (size)
Show answer
* (pointer) — Correct. * declares a pointer.
-
Match each Span and unsafe method
- ReadOnlySpan<char>
- Zero-copy char view
- IndexOf(':')
- Find first colon
- Slice(0, n)
- Take first n chars
Next lesson: Channels and concurrent