В .net есть два типа: ReadOnlySpan<T> и ReadOnlySequence<T>. Первый представляет собой абстракцию над неизменяемым непрерывным массивом из элементов T, второй - цепочку из подобных отрезков. Первый удобен, когда вам надо написать метод, оперирующий над а-ля массивами, которые могут быть: обычными массивами, массивами на стеке (привет, stackalloc), массивами в неуправляемой памяти и так далее. Его оверхед я рассматривал ранее.
ReadOnlySequence<T>
же чаще всего (на мой взгляд) полезен там, где у нас есть чтение из сети, потому что если вам по сети едет один миллион (или хотя бы тысяча) 64-битных чисел, вряд ли они приедут к вам одной пачкой. Надеяться можно, но это далеко не всегда так. Чаще всего это будет какая-то цепочка из буферов.
Я пытаюсь написать библиотеку, которой будет удобно пользоваться для обоих случаев и тут мы натыкаемся на то, что надо писать два раза один и тот же код, но для разных типов. Ниже будет выдержка, полный код тут.
И у нас есть проблемы:
- Оба типа являются структурами, которые не реализуют никаких интерфейсов, следовательно, мы не можем написать общий код для какого-то
IReadOnlyCollection<T>
. - Мы не можем сделать код generic, потому что
ReadOnlySpan<T>
- это специальная stack-only структура, которая не может быть типом-параметром генерик-метода. - Мы не можем создать
ReadOnlySequence<T>
изReadOnlySpan<T>
без копирования, потому чтоReadOnlySequence<T>
состоит не из спанов, а изReadOnlyMemory<T>
, которая похожа на Span, но не stack-only и создание памяти из отрезка - это копирование. - Нельзя заменить в сигнатуре
Read
ReadOnlySpan<T>
наReadOnlyMemory<T>
, потому что они разные.ReadOnlyMemory<T>
не может использоваться для работы с неуправляемой памятью или массивами на стеке, аReadOnlySpan<T>
- может, т.е. он может представить гораздо больше “массивов” единообразно. - Цепочку из нескольких буферов тоже нельзя представить в виде одного указателя и длины (чем является
ReadOnlySpan<T>
) без копирования по понятным причинам.
Я пока не вижу другого способа, кроме как дублировать код. Вспоминается старый добрый С++, в котором можно было бы (если мне не изменяет память) сделать примерно вот так:
comments powered by Disqus