如何从ArraySegment中获取字节数组

5
如果有人给我一个指向更大缓冲区的ArraySegment<byte> foo,那么将这个段复制到一个新的byte[]中的惯用方法是什么?
我尝试访问foo.Array,但这似乎指向更大缓冲区的开头,而不是该段的开头。
例如,更大的缓冲区可能是"blahfoobar",而ArraySegment指向"foo"。我想获取只包含"foo"的byte[]
我确信这很简单,但由于来自C ++,我无法理解在c#中使用的术语。

我看到 ArraySegment 实现了 ICollection 接口,所以你必须要有 ToArray 方法。 - PiGi78
@PiGi78 这只适用于 .Net 4.5 及以上版本和 .Net Core,它实现了比 ICollection 更多的迭代类型:https://dev59.com/BG445IYBdhLWcg3w_PG3#7907024 - OP 看起来你需要遍历 ArraySegments,将其转换为数组并将数组连接在一起。 - Jeremy Thompson
2个回答

4

创建一个新的数组完全没有意义,因为API的目的是表示现有的段。在较新的.NET版本中,Span<T>ReadOnlySpan<T>会是更好的选择 - 它们允许您创建一个对连续内存的抽象,而无需让使用者担心 Offset 等问题,因为这可以由外部强制执行。在Span<T>ReadOnlySpan<T>上有构造函数,它们允许您处理方面,以便使用者永远不需要知道它们,同时了解到在最近的运行时:JIT将在范围上消除边界检查。


太棒了。我会看看我的版本是否适合使用 span。我熟悉 C++ gsl::span 并且喜欢它们。 - Jeffrey
1
@Jeffrey 注意:如果您需要将范围存储为堆上的字段,则需要[ReadOnly]Memory-T;内存基本上是“当您需要时,我可以给您一个跨度”的意思——它也可以被称为“SpanSource”或类似的名称。您可以在数组段(以及其他一些范围,包括自定义分配器)上创建内存。 - Marc Gravell

1
using System;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        private static readonly byte[] _initArray = Encoding.ASCII.GetBytes("blahfoobar");

        //private static byte[] ArraySegmentToArray(ArraySegment<byte> segment)
        //{
        //    var result = new byte[segment.Count];

        //    for (int i = 0; i < segment.Count; i++)
        //    {
        //        result[i] = segment.Array[i + segment.Offset];
        //    }

        //    return result;
        //}

        private static byte[] ArraySegmentToArray(ArraySegment<byte> segment) =>
            segment.ToArray();

        static void Main(string[] args)
        {
            var segFoo = new ArraySegment<byte>(_initArray, 4, 3);

            var test = ArraySegmentToArray(segFoo);
        }
    }
}

当然,这是一种不好的做法。因为如果你将段转换成数组,你就会分配内存,而如果你使用ArraySegment作为指针,你就不会分配内存,实际上,这就是使用ArraySegment的主要思想,因为如果不这样做,数组可能会作为参数提供 :) P.S.注释的代码只是为了理解思路。

有所帮助。我喜欢它明确地显示了从.Array[]需要segment.Offset的事实。但是,肯定有一种直接获取偏移数组的方法,对吧? - Jeffrey
ToArray 的运行时成本是什么?请确认它返回现有的内存,而不是制作副本。 - Jeffrey
2
@Jeffrey OP 请求“将其转换为全新的 byte[]吗?”,而这段代码确实做到了。我不确定您为什么认为它应该做其他事情...您如何能够创建一个没有为其分配新空间的新数组呢?即使在您声称熟悉的 C++ 中也不是这样工作的... - Alexei Levenkov
运行时成本是分配 = 字节 x 请求数量 + 代码执行 :) 如果您正确使用ArraySegment,则仅涉及代码执行。 - Ivan Khorin
@AlexeiLevenkov,OP(和我自己)所说的“新鲜的新byte []”是指在偏移位置上表现得像数组的东西。就像char* fresh = original + offset;这样,它不会分配内存。ToArray()对我来说很有效,因为代码的其余部分期望一个byte[]。不幸的是,它会分配一个副本。 - Jeffrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接