span<T> and streams

23

我已经阅读了一段时间关于span的内容,并尝试着去实现它。然而,虽然我可以让span起作用,但我无法弄清楚如何使流接受它,就像示例中那样。其他示例也显示了int.parse支持span,但我找不到能够实现这一点的重载或扩展。

我已在.net standard 2.0.net core 2.0中尝试过。

请指导我正确的方向以使其起作用。

代码示例:

Span<Byte> buffer = new Span<byte>();
int bytesRead = stream.Read(buffer);

1
你能具体说明一下吗?但如果你是在谈论从流中读取数据,可以尝试使用这个代码:reader.ReadBlock(charArray, 0, span.Length); - SunAwtCanvas
你能否编辑并发布一些代码,以便我们理解您的需求? - Kyle B
2
不,我说的是使用新的 span<T> 类从流中读取数据。它与您通常使用的字节数组或文本类不同。 - Christopher James Woods
1
@Denise,这个问题是关于“跨度”而不是“块”的。这是一个完全有效的问题。 - Panagiotis Kanavos
2个回答

16

我本以为会是这样的。但我在任何网站上都找不到相关链接。感谢您的帮助。我可能会等到它退出预览。 - Christopher James Woods
@ChristopherJamesWoods,你不必这样做。2.1 版本可以并存,并且在创建新项目时可以选择使用哪个运行时版本。此外,MS Build 就在眼前。下周可能会有一些有趣的公告。 - Panagiotis Kanavos
@PanagiotisKanavos 当您关闭和处理流时会发生什么?Span<T>会指向虚空吗? - silkfire
@silkfire 这个方法使用调用者提供的跨度。它们将存在于调用者需要它们的整个时间内。 - Panagiotis Kanavos

6

让我们看一个我手头方便的例子,其中Span<T>恰好来自PipeWriter

var bufferSpan = pipeWriter.GetSpan(count);
stream.Write( /* Darn, I need an array, because no Span<T> overloads outside Core 2.1! */ );

尝试使用 Memory<T> 而不是 Span<T>,因为你可以获取基础数组(除了在某些特殊情况下)。
var bufferMemory = pipeWriter.GetMemory(count); // Instead of GetSpan()
var bufferArraySegment = bufferMemory.GetUnderlyingArray();
stream.Write(bufferArraySegment.Array, bufferArraySegment.Offset, bufferArraySegment.Count); // Yay!

GetUnderlyingArray() 这里是一个小的扩展方法:


/// <summary>
/// Memory extensions for framework versions that do not support the new Memory overloads on various framework methods.
/// </summary>
internal static class MemoryExtensions
{
    public static ArraySegment<byte> GetUnderlyingArray(this Memory<byte> bytes) => GetUnderlyingArray((ReadOnlyMemory<byte>)bytes);
    public static ArraySegment<byte> GetUnderlyingArray(this ReadOnlyMemory<byte> bytes)
    {
        if (!MemoryMarshal.TryGetArray(bytes, out var arraySegment)) throw new NotSupportedException("This Memory does not support exposing the underlying array.");
        return arraySegment;
    }
}

总的来说,这使得你可以在不进行任何复制的情况下,将带有“现代”返回类型的方法与“旧”的框架重载结合使用。 :)

这仅适用于只读内存。事实上,“Stream” API 相当有问题:byte[] 不能代替“一块内存块”。在内部,Read(Span<T>) 通过一个中间数组进行复制。 - Kuba hasn't forgotten Monica
1
@KubaOber 我认为你永远无法基于 (ReadOnly)Span<byte> 创建一个 Stream。Spans 是仅限堆栈的类型,而流则不是。流可能会超出范围。在其当前形式下,Stream 最多只能基于 (ReadOnly)Memory<byte>。如果您想要包装一个 span,则需要一个仅限堆栈的流。 - Timo
当然,Span和Memory是相辅相成的,两者都应该得到支持(支持其中一个必须意味着支持另一个,否则API就是有问题的)。 - Kuba hasn't forgotten Monica
其实我发现我把事情搞混了。问题本身是关于从流中读取到一个范围(span)中,这要求 .NET Core 2.1+,或者你传递自己的数组,并且之后你得到一个覆盖该数组的 span(这可能不是 OP 寻找的)。我现在意识到,我的回答涉及使用 Memory<byte> 向流中 写入 数据,在没有接受 span 的 Core 2.1 重载方法的情况下。第三种情况是构建基于 Memory<byte> 数据的流,这在 span 中没有意义,因为仅限堆栈的流将具有有限的用途。 - Timo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接