Span<T> и потоки в.NET Framework

Я работаю с сетевыми буферами и потоками, и Span и Memory будут идеально соответствовать требованиям приложения.

Что касается этого вопроса, я бы хотел, чтобы поток принимал Span в качестве параметра. Я знаю, что это реализовано в.NET Core 2.1, но мне было интересно, есть ли способ получить эту функциональность также в.NET Framework? (Я использую 4.7.1)

Что-то вроде:

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

2 ответа

Решение

Мне удалось решить эту проблему, написав метод расширения для класса 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); }
    }

К сожалению, поскольку эта функциональность еще не реализована в.Net Standard, она не включена в.Net Framework.

Редактировать: я помню, что я где-то читал, что есть предварительный пакет NuGet, который можно использовать с.Net Framework

Проверьте NuGet с System.Memory

Принятое решение отлично работает!

Однако в некоторых ситуациях, когда я использую общий проект, нацеленный на.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.

Другие вопросы по тегам