ReadOnlySpan<char> r = someString.AsSpan();
string newStr = new string(span);
或使用 string.Create(length, state, spanAction)
以避免額外中間分配的多次拷貝。MemoryMarshal.AsBytes<T>(span)
將 Span<T>
轉為 Span<byte>
(注意對齊與相依型別安全性)。Encoding.UTF8.GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
與 Encoding.UTF8.GetString(ReadOnlySpan<byte> bytes)
。像是以下例子,想要高效率 UTF-8 編碼到預先分配的 buffer
using System;
using System.Text;
Span<byte> outBuf = stackalloc byte[128];
ReadOnlySpan<char> text = "Hello 世界".AsSpan();
int written = Encoding.UTF8.GetBytes(text, outBuf);
// 現在 outBuf.Slice(0, written) 包含 UTF-8 bytes
要注意
Span<T>
放到類的欄位或用作 async/await 中的局部變數會導致編譯錯誤或不可預期的行為,編譯器會阻止這些用法。stackalloc
或來自非托管記憶體的 Span<T>
時要注意生命週期,千萬不要將資料引用回傳給呼叫端。若要回傳,可考慮 Memory<T>
搭配 MemoryPool。Memory<T>.Pin()
與 MemoryMarshal.GetReference()
可以在需要 pin 時使用,但務必在 fixed
或受控區塊內使用以避免 GC moving 導致的問題。建議
Span<T>
來避免分配。若操作必須跨越非同步邊界,使用 Memory<T>
+ IMemoryOwner<T>
(MemoryPool)。Substring
在熱路徑建立大量臨時字串,改用 ReadOnlySpan<char>
。Encoding
的 span-overloads 以避免中間陣列。像是我們可以用 Span 實作簡單的 CSV 欄位拆分,能達到同步、無分配
using System;
void PrintCsvFields(ReadOnlySpan<char> line)
{
while (!line.IsEmpty)
{
int idx = line.IndexOf(',');
if (idx == -1)
{
Console.WriteLine(line.ToString());
break;
}
var field = line.Slice(0, idx);
Console.WriteLine(field.ToString());
line = line.Slice(idx + 1);
}
}
PrintCsvFields("a,b,c,d".AsSpan());
在微軟設計中,字串提供了方便且不可變的字元序列表現,Span<T>
提供低延遲、零分配的同步操作視圖;Memory<T>
則是在需要可傳遞、長期保留或跨 async 邊界時的安全選擇。