span and streams

2019-05-03 07:55发布

I have been reading about span for a while now, and just tried to implement it. However, while I can get span to work I cannot figure out how to get a stream to accept it like they do in the examples. Other examples show int.parse supporting spans as well but I can't find overloads or extensions that make it possible.

I have tried it in both .net Standard 2.0 and .net core 2.0.

Please point me in the right direction to make this work.

Edit: Code example would be:

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

标签: c# .net-core
2条回答
贼婆χ
2楼-- · 2019-05-03 08:39

Span results from streams are supported in .NET Core 2.1. If you check the current source code of eg Stream you'll see it has overloads like Read(Span) that read into a Span<byte> instead of byte[], or Write(ReadOnlySpan) that can write out a ReadOnlySpan<byte> instead of a byte[], overloads that use Memory etc.

To target .NET Core 2.1, you'll have to install at least Visual Studio 2017 15.7 Preview 4 or the latest SDK for .NET Core 2.1

查看更多
闹够了就滚
3楼-- · 2019-05-03 08:48

Let's look at an example that I have handy, where the Span<T> happens to come from PipeWriter.

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

Try to get a Memory<T> instead of Span<T>, for which you can get the underlying array (except under some exotic circumstances).

var bufferMemory = pipeWriter.GetMemory(count); // Instead of GetSpan()
var bufferArraySegment = bufferMemory.GetUnderlyingArray();
stream.Write(bufferArraySegment.Array, bufferArraySegment.Offset, bufferArraySegment.Count); // Yay!

GetUnderlyingArray() here is a small extension method:

/// <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;
    }
}

All in all, this lets you use the methods with a 'modern' return type in combination with the 'old' framework overloads - without any copying. :)

查看更多
登录 后发表回答