Span<T> and streams in .NET framework

4.9k Views Asked by At

I am working with network buffers and streams, and Span and Memory would fit perfectly in the application requirements.

As per this question, I would like to get a Stream to accept Span as a parameter. I know that is implemented in .NET Core 2.1, but I was wondering if there's a way to get this functionality in .NET Framework as well? (I am using 4.7.1)

Something like:

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

There are 3 best solutions below

3
On BEST ANSWER

I managed to solve this by writing an extension method for the Stream class and implementing .NET Core's default behaviour for dealing with 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); }
    }

and

    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); }
    }
3
On

Unfortunately, since this functionality is not yet implemented in .Net Standard it is not included in .Net Framework.

Edit: I remember that I read from somewhere that there is pre-release NuGet package which can be used with .Net Framework

Check NuGet with System.Memory

0
On

The accepted solution works great!

However, in some situations where I use a shared project targeting both .NET Core and .NET Framework together, I am using both an array and a Span<T>:

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

#if NETCOREAPP3_1

stream.Read(buffer);

#else

stream.Read(_buffer);

#endif

In this way, I can avoid the small overhead of renting/copying/returning an array from ArrayPool.