.NET Core 2.1 和 C# 7.2 帶來了 Span 的原生支持,原本需要使用不安全代碼操作的內存塊現在可以使用安全的方式來完成。此前在性能和穩定性上需要有所取舍,而現在可以兼得了。
簡單的例子
先來看一個字符串處理時使用 Span<T>
的最簡單的例子:
using System;
using System.Text;
namespace Walterlv.Demo.StringSpan
{
internal class Program
{
static void Main(string[] args)
{
var text = "https://walterlv.github.io/";
var nameSpan = text.AsSpan(8, 8);
var builder = new StringBuilder("Hello ");
builder.Append(nameSpan);
builder.AppendLine("!");
Console.WriteLine(builder.ToString());
}
}
}
這個例子是從 https://walterlv.github.io/ 字符串中取出第 8 個字符開始長度為 8 的部分,隨后與其它字符串進行拼接。最后,我們得到了拼接的字符串:
這種方式取出字符串替代了 SubString
這種會額外生成臨時字符串的方式。如果上述代碼發生在較大或較多文本的處理中,那么反復的拼接將生成大量的臨時字符串,造成大量 GC 壓力;而使用 Span<T>
將不會額外生成任何臨時字符串。
語言/框架的支持
然而,只有 .NET Core 2.1 是原生支持字符串的 AsSpan<T>
方法的,.NET Core 2.0、.NET Framework 4.7.2 是不支持的。.NET Core 2.0 可以無視,因為有了 2.1。但 .NET Framework 的低版本卻不能無視,因為用戶的計算機上通常都是安裝低版本的 .NET Framework。
然而我們可以安裝 System.Memory,以在低版本的 .NET 中獲得字符串擴展方法 AsSpan<T>
的支持。
那么問題來了,低版本的 .NET StringBuilder
中並沒有提供 Append(ReadOnlySpan<char>)
方法,於是我們即便使用高性能的方式得到了字符串的一個片段,依然無法將其反復進行拼接。
這真是一個悲傷的故事!
低版本 .NET 中有限的字符串性能提升
缺少了 StringBuilder
對 ReadOnlySpan<char>
的支持,廣泛使用的字符串拼接功能便沒有辦法獲得 Span 的支持。
不過,System.Memory 中提供了其它有限的字符串處理支持,來源於以下兩個類型:
System.Buffers.Text.Utf8Parser
System.Buffers.Text.Utf8Formatter
前者提供從 ReadOnlySpan<char>
到 Int32
、Double
、DateTime
、Guid
等類型的解析,后者提供相反的轉換。
期待 Microsoft 在未來版本的 System.Memory 庫中提供對字符串拼接在低版本 .NET 生態中的支持。