在.NET框架中,Span<T>和流(streams)是什么?

8
我正在处理网络缓冲区和流,Span 和 Memory 会完美地满足应用程序的要求。
根据这个问题,我想获取一个可以接受 Span 参数的 Stream。我知道在 .NET Core 2.1 中已经实现了此功能,但我想知道是否有办法在 .NET Framework 中实现相同的功能呢?(我使用的是4.7.1版本)
例如:
Span<Byte> buffer = new Span<byte>();
stream.Read(buffer);

3
你有一个实现它的代码链接,考虑复制/粘贴它。暂停一下看看它做了什么,注意它在底层仍然使用byte[]。因此,使用Span并没有真正让你超前。除非你需要将byte[]切片成更小的块,否则这种优化并不会产生好处,而你现在已经可以这样做了。 - Hans Passant
3个回答

11

我通过为Stream类编写扩展方法,并实现.NET Core对于Span处理的默认行为,成功解决了这个问题。

    public static int Read(this Stream thisStream, Span<byte> buffer)
    {
        byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
        try
        {
            int numRead = thisStream.Read(sharedBuffer, 0, buffer.Length);
            if ((uint)numRead > (uint)buffer.Length)
            {
                throw new IOException(SR.IO_StreamTooLong);
            }
            new Span<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
            return numRead;
        }
        finally { ArrayPool<byte>.Shared.Return(sharedBuffer); }
    }

并且

    public static void Write(this Stream thisStream, ReadOnlySpan<byte> buffer)
    {
        byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
        try
        {
            buffer.CopyTo(sharedBuffer);
            thisStream.Write(sharedBuffer, 0, buffer.Length);
        }
        finally { ArrayPool<byte>.Shared.Return(sharedBuffer); }
    }

1
在这行代码 throw new IOException(SR.IO_StreamTooLong); 中,SR 是什么? - Chuck Savage
可能是我用于处理IO异常的自定义异常类。 - Tomy
2
@Tomy SR 是微软大多数 .NET 程序集中的一个 内部静态类;"SR" 是 "String resources" 的缩写,它是 ResourceManager 的简写包装器,用于检索本地化的异常消息。 - Dai

1

很遗憾,由于这项功能尚未在 .Net Standard 中实现,因此它不包含在 .Net Framework 中。

编辑:我记得我从某个地方读到有一个预发布的 NuGet 包,可以与 .Net Framework 一起使用。

检查 NuGet,使用 System.Memory


我已经做了!这使我能够使用Span和Memory结构,但没有添加所需的Stream重载……或者至少我无法弄清楚如何做到这一点。 - Tomy
如果您觉得这个答案有帮助,请考虑点赞和/或将其标记为接受的答案。 - Derviş Kayımbaşıoğlu
你说:“不幸的是,由于这个功能在 .Net Standard 中尚未实现,因此它不包括在 .Net Framework 中。”请注意,你搞反了。.NET Framework 先出现,然后才是 .NET Standard 2.0。也就是说,由于它不在 .NET Framework 中,所以它不能在 .NET Standard 2.0 中。如果他们将其添加到 .NET Standard 中,它并不会神奇地成为 .NET Framework 支持的内容。事实上,你会发现这个方法重载在 .NET Standard 中得到了支持。特别是在版本 2.1 中。但是 .NET Framework 固定在 .NET Standard 2.0 上。 - Mike Christiansen

-2

这个解决方案非常好!

然而,在一些情况下,我使用一个共享项目,同时针对 .NET Core 和 .NET Framework,我同时使用了数组和 Span<T>

var _buffer = new byte[1024*1024];
Span<Byte> buffer = _buffer;

#if NETCOREAPP3_1

stream.Read(buffer);

#else

stream.Read(_buffer);

#endif

这样,我就可以避免从ArrayPool租用/复制/返回数组所带来的小开销。


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