【问题标题】:Can I get a pointer to a Span?我可以获得指向 Span 的指针吗?
【发布时间】:2019-06-12 19:57:17
【问题描述】:

我有一个(ReadOnly)Span<byte>,我想从中解码一个字符串。

仅在 .NET Core 2.1 中,我有新的重载来从中解码字符串,而无需复制字节:

Encoding.GetString(ReadOnlySpan<byte> bytes);

在 .NET Standard 2.0 和 .NET 4.6(我也想支持)中,我只有经典的重载:

Encoding.GetString(byte[] bytes);
Encoding.GetString(byte* bytes, int byteCount);

第一个需要将字节复制到我想避免的数组中。
第二个需要一个字节指针,所以我想从我的跨度中获取一个,比如

Encoding.GetString(Unsafe.GetPointer<byte>(span.Slice(100)))

...但我没有找到一个实际的方法。我试过void* Unsafe.AsPointer&lt;T&gt;(ref T value),但我无法将跨度传递给它,也没有找到另一种处理指针(和跨度)的方法。

这有可能吗,如果可以,怎么做?

【问题讨论】:

  • 输入[ReadOnly]Span&lt;T&gt;.GetPinnableReference()。如果使用 C# 7.3,利用它就像 fixed (byte* bytes = span) 一样简单——它至少可以为 .NET 4.5.2 编译,我还没有测试它是否也能真正工作(我只有以后安装的框架)。
  • 在之前的 C# 版本中,您可以使用ref GetPinnableReference() 的返回值作为Unsafe.AsPointer 的参数。您至少需要 C# 7.0 才能使用 ref locals。
  • @JeroenMostert 这太棒了,我使用的是 C# 7.3,它运行起来像丝绸一样顺畅。你想发布一个关于它的答案以便我接受吗?
  • 在 ILSpy 的帮助下,我实际上也为早期版本找到了更方便的语法。也没有经过测试,但由于返回的指针是相同的,我假设它可以工作。

标签: c# .net-standard-2.0 .net-4.6 .net-core-2.1


【解决方案1】:

试试这个:

Span<byte> bytes = ...;
string s = Encoding.UTF8.GetString((byte*)Unsafe.AsPointer(ref bytes.GetPinnableReference()),
    bytes.Length);

【讨论】:

  • 谢谢!我在 IntelliSense 的任何地方都没有看到 GetPinnableReference()。但是,这似乎不适用于ReadOnlySpan&lt;byte&gt;(它不能将其作为 ref 传递,因为它是只读的);但它适用于我最初的问题(直到现在我才意识到我有一个ReadOnlySpan,对不起!)。
  • @RayKoopa:顺便说一句,你看不到方法的原因是因为它是explicitly hidden as feature。当它被称为DangerousGetPinnableReference 时,它又回来了;此后它已被降级为“实际上并不那么危险”,但该方法仍处于隐藏状态。
  • ReadOnlySpan 提出的替代方案不正确!首先将它存储在一个变量中并获取其中的ref,从而为您提供对本地byte 的引用,不是跨区数组。以这种方式访问​​第一种以外的任何元素都会产生垃圾。
  • @JeroenMostert 我实际上记得“危险”方法名称。我没有跟进最近的变化,感谢您澄清这一点。
【解决方案2】:

如果您有 C# 7.3 或更高版本,则可以使用对 fixed 语句的扩展,该语句可以在类型上使用任何适当的 GetPinnableReference 方法(SpanReadOnlySpan 具有):

fixed (byte* bp = bytes) {
    ...
}

当我们处理指针时,这当然需要unsafe 上下文。

C# 7.0 到 7.2 没有这个,但允许以下:

fixed (byte* bp = &bytes.GetPinnableReference()) {
    ...
}

【讨论】:

  • 很酷。我接受这个作为答案,因为它还涵盖了新的 C# 7.3 语法。
猜你喜欢
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 2014-02-19
  • 2011-02-01
相关资源
最近更新 更多