当前位置 : 主页 > 网络编程 > net编程 >

关于 Span 的一切:探索新的 .NET 明星: 2. Span<T> 是如何实现的?

来源:互联网 收集:自由互联 发布时间:2023-10-08
2. SpanT 是如何实现的? ​​https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/january/csharp-all-about-span-exploring-a-new-net-mainstay#how-is-spant-implemented​​ 内容列表: ​​1. SpanT 是什么?​​ ​​

2. Span<T> 是如何实现的?

​​https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/january/csharp-all-about-span-exploring-a-new-net-mainstay#how-is-spant-implemented​​

内容列表:

  • ​​1. Span<T> 是什么?​​
  • ​​2. Span<T> 是如何实现的?​​
  • ​​3. 什么是 Memory<T>,以及为什么你需要它?​​
  • ​​4. Span 和 Memory 是如何与 .NET 库集成的?​​
  • ​​5. NET 运行时​​
  • ​​6. C# 语言和编译器受到什么影响?​​

通常开发人员并不需要理解其使用的库是如何实现的。不过,对于 Span<T> 来说,它值得至少理解它后面的细节,因为这些细节影响到它的性能和使用方式的约束。

首先,Span<T> 是包含一个 ref 和长度的值类型,参考定义如下:

public readonly ref struct Span<T>
{
private readonly ref T _pointer;
private readonly int _length;
...
}

该 ​​ref T​​ 字段的概念在一开始可能奇怪 - 但是,在 C# 中并不能实际定义 ref T 字段,甚至在 MSIL 中。但是 Span<T> 实际上被开发用来使用运行时的特定内部类型,可以被看作 JIT,使用 JIT 生成等价的 ref T 字段。考虑更为常见的 ref 用法:

public static void AddOne(ref int value) => value += 1;
...
var values = new int[] { 42, 84, 126 };
AddOne(ref values[2]);
Assert.Equal(127, values[2]);

这段代码通过引用传递数组中的一个位置,这样你得到一个在堆栈上的 ref T。该 Span<T> 与 ref T 是相同的思想,简单地在 struct 中封装。直接包含此类 ref 或者间接包含的类型被称为仿 ref 类型,C# 7.2 编译器使用 ref struct 签名来定义此类仿 ref 类型。

通过该总结,明确了两件事:

  1. 通过这种方式定义的 Span,可以与数组一样高效:对 Span 的索引不需要从指针和其开始位置开始计算,因为 ref 字段已经封装了它们。( 相反,ArraySegment 有独立的 offset 字段,使得它在索引访问和分发时都变得更为昂贵 )
  2. Span 的本质是仿 ref 类型,带来了与 ref T 字段一样的约束。

第二个问题带来了有趣的分支,这些分支导致 .NET 包含由 Memory<T> 引导的第二中类型。

上一篇:MVC学习以及研究
下一篇:没有了
网友评论