'Memory sequence - use ArrayPool instead and make each chunk 128 bytes long
I had to create a MakeSequence method for the Message implementation. The Message class is part of a library, so I cannot change it. If you have a look at the Message class, you'll see that using an ArrayPool is mandatory and I would also like each chunk to be 128 bytes long.
In my attempt I used Encoding.UTF8.GetBytes which is wrong and results in an ArgumentException thrown at .Return(...) in Message.Dispose.
System.ArgumentException: The buffer is not associated with this pool and may not be returned to it. (Parameter 'array') at System.Buffers.TlsOverPerCoreLockedStacksArrayPool`1.Return(T[] array, Boolean clearArray)
So how do I make MakeSequence use an ArrayPool instead and if the input array is greater than 128 bytes, to split it on 128 bytes long chunks?
var bytes = Encoding.UTF8.GetBytes("hellohellohellohellohellohellohellohello");
var sequence = Helpers.MakeSequence(bytes);
var message = new Message(sequence);
...
message.Dispose(); // System.ArgumentException: The buffer is not associated with this pool and may not be returned to it
public readonly struct Message : IDisposable
{
public Message(ReadOnlySequence<byte> sequence)
{
Sequence = sequence;
}
public ReadOnlySequence<byte> Sequence { get; }
public void Dispose()
{
foreach (var chunk in Sequence)
{
if (MemoryMarshal.TryGetArray(chunk, out var segment))
{
ArrayPool<byte>.Shared.Return(segment.Array!);
}
}
}
}
public static class Helpers
{
public static ReadOnlySequence<byte> MakeSequence(params byte[][] parts)
{
if (parts.Length == 0)
{
return ReadOnlySequence<byte>.Empty;
}
if (parts.Length == 1)
{
return new ReadOnlySequence<byte>(parts[0]);
}
Chunk<byte> first = null;
Chunk<byte> last = null;
foreach (var part in parts)
{
if (first == null)
{
first = new Chunk<byte>(part);
last = first;
}
else
{
last = last.Add(part);
}
}
return new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length);
}
}
public sealed class Chunk<T> : ReadOnlySequenceSegment<T>
{
public Chunk(ReadOnlyMemory<T> memory)
{
Memory = memory;
}
public Chunk<T> Add(ReadOnlyMemory<T> segment)
{
var chunk = new Chunk<T>(segment)
{
RunningIndex = RunningIndex + Memory.Length
};
Next = chunk;
return chunk;
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
