参考连接:
1.https://docs.microsoft.com/zh-cn/archive/msdn-magazine/2018/january/csharp-all-about-span-exploring-a-new-net-mainstay
2.https://www.cnblogs.com/dacc123/p/10644816.html
3.https://www.cnblogs.com/tiger-wang/p/14029853.html
介绍:
.NET Core 2.1 和 C# 7.2 带来了 Span 的原生支持,原本需要使用不安全代码操作的内存块现在可以使用安全的方式来完成。此前在性能和稳定性上需要有所取舍,而现在可以兼得了。
Span< T > : 结构体,值类型 。相当于C++ 中的指针,它是一段连续内存的引用,也就是一段连续内存的首地址。使用的是堆栈内存。有了Span< T >,我们就可以不在unsafe的代码块中写指针了。
使用:
应用1:允许截取数组中的一段,直接通过指针操作。在使用中,Span确保了内存和数据安全,而且几乎没有开销。
var arr = new byte[10]; Span<byte> bytes = arr; bytes [0] = 42;
应用2:高效的字符串操作。string.Substring() 函数,实际上是在堆中额外创建了一个新的 string 对象,把字符 copy 过去,再返回这个对象的引用。而相对应的 Span< T > 的Slice() 函数则是直接在内存中返回子串的首地址引用,此过过程几乎不分配内存,并且十分高效。因此可以用来做高效的字符串截取,也可以配合StringBuilder进行高效的字符串拼接。注:ReadOnlySpan为只读的Span。
ReadOnlySpan<char> t = "abcde".AsSpan(2,2); ReadOnlySpan<char> t2 = tts.Slice(1, 3); int position = t.IndexOf(t2); string s = t.ToString(); StringBuilder sb = new StringBuilder(); sb.Append(t);
限制:
Span使用的是堆栈内存。所有指向堆栈的指针都不能存储在托管堆上。因为方法结束时,堆栈会被释放,指针会变成无效值,如果再使用,就是内存溢出。
因此Span实例也不能驻留在托管堆上,而只能驻留在堆栈上。这又引出一些限制。
1.Span不能作为非堆栈类型的字段
2.Span不能有接口实现
3.Span不能是异步方法的参数或局部变量
4.Span不能是泛型的代入参数
以上限制可以使用Memory<T>解决,这与处理 Span 基本相同,不同之处在于 Memory<T> 是不类似引用的结构,可以存在于堆上。然后,若要执行同步处理,可以从其属性中获取 Span<T>。