快速将数组的一部分复制到列表中的方法是什么?

4

C#的List<>类有一组CopyTo函数,这些函数可以使用快速内存块复制将List<>对象内部的数组内容提取到另一个数组中。

那么是否有一种方法可以反过来做呢?它可能看起来像这样...

var buffer = new List<byte>();
buffer.AddRange(afewbytes);
buffer.AddFromArray(myArray, startIndex, countBytesToCopy);
buffer.AddRange(afewmorebytes);

由于我的List是List<byte>类型,我希望避免逐个字节复制的循环。

3个回答

7
List<T>(IEnumerable<T>) 构造函数将使用 ICollection<T>.CopyTo,如果集合实现了 ICollection<T>,那么 byte[] 将会这样做。
如果你只想提取数组的一部分,那么这并不能直接帮到你,但是你可以创建自己的 ByteArraySegment 类,实现 ICollection<byte> 并使用 Buffer.BlockCopy 或其他方法来实现 CopyTo 操作。
public class ByteArraySegment : ICollection<byte>
{ 
    private readonly byte[] array;
    private readonly int start;
    private readonly int count;

    public ByteArraySegment(...)
    {
        // Obvious code
    }

    public void CopyTo(byte[] target, int index)
    { 
        Buffer.BlockCopy(array, start, target, index, count);
    }

    // Other ICollection<T> members
}

然后:

List<byte> bytes = new List<byte>(new ByteArraySegment(myArray, start, count));

(或使用具有相同优化的AddRange。)

1
非常感谢!我已经编辑了我的问题,以澄清我正在寻找一个高效的Add而不是构造函数,但从David答案的评论来看,你的类应该也适用于AddRange。 - billpg
我们真的确定我们可以信任这个Jon Skeet吗? ;) - Brandon
你永远无法确定Jon Skeet...有些人说,他甚至不是真实存在的! - rae1

4

要复制数组的一部分,请将数组包装在一个ArraySegment中,指定段的索引和计数。使用列表的AddRange方法将ArraySegment添加到列表中。AddRange会使用ArraySegment.CopyTo,后者使用Array.Copy,这是快速的


这应该是被接受的答案! - Aminos

3
List.AddRange(myArray) 应该非常高效。
根据MSDN的说明:"如果新的 Count(当前 Count 加上集合的大小)将大于 Capacity,则 List 的容量会通过自动重新分配内部数组以容纳新元素而增加,并且在添加新元素之前,现有元素会被复制到新数组中。"

List<byte>.AddRange 接受一个 IEnumerable<byte> 作为参数。这难道不会逐个处理每个字节吗?(而不是作为一个块) - billpg
2
不,它会将其解释为ICollection并执行Array.Copy操作,这与memcpy一样快(它可能在底层使用了memcpy)。 - Asik
1
@Asik,使用AddRange和Jon答案中的代码组合应该就可以解决问题了。非常感谢! - billpg

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