1

好的,也许我只是懒惰,但这可能是互联网上的一个很酷的问题。

我知道这Buffer.BlockCopy(...)Array.Copy(...)使用byte[]. 我正要编写一个CloneBuffer助手,它会创建一个与源数组大小相同的数组,然后将源数组复制到其中,但Buffer.BlockCopy(...)我却写了:

public void Send(byte[] data) {
    // Copy caller-provided buffer
    var buf = data.ToArray();

    // Start async send here and return immediately
}

有谁知道该ToArray()方法是否是特殊的,byte[]或者这是否会比 慢BlockCopy

4

2 回答 2

7

您可以使用反射器程序(例如ILSpy )查看 Microsoft .NET 程序集。

这告诉我,实现System.Linq.Enumerable::ToArray()是:

public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
    // ...
    return new Buffer<TSource>(source).ToArray();
}

内部结构的构造函数Buffer<T>

  • 如果源可枚举实现ICollection<T>,则:
    • Count分配一个元素数组,并且
    • 用于CopyTo()将集合复制到数组中。
  • 否则:
    • 分配一个包含 4 个元素的数组,并且
    • 开始枚举 IEnumerable,将每个值存储在数组中。
    • 数组是否太小?
      • 创建一个大小是旧数组两倍的新数组,
      • 并将旧数组的内容复制到新数组中,
      • 然后改用新数组,然后继续。

如果Buffer<T>.ToArray()内部数组的大小与其中的元素数匹配,则简单地返回内部数组;否则将内部数组复制到具有确切大小的新数组。

请注意,该类是内部的,与您提到Buffer<T>的类无关。Buffer

所有的复制都是使用Array.Copy().

因此,总结一下:所有复制都是使用完成的Array.Copy(),并且没有对字节数组进行优化。但我不知道它是否比Buffer.BlockCopy(). 唯一知道的方法是测量。

于 2013-11-13T21:30:41.993 回答
0

是的,它会变慢。

当您查看System.Array 方法的文档时,没有定义System.Array.ToArray(). 其实看继承/接口树,就是一路回溯,[IEnumerable.ToArray()][2]才找到这个方法。由于这是仅使用 IEnumerable 的功能来实现的,因此它在开始执行时无法知道结果数组的大小。相反,它使用加倍算法在运行时构建数组。因此,您最终可能会在制作副本的过程中创建并丢弃多个数组,并在销毁/重新创建每个中间缓冲区的过程中多次复制这些初始项目。

如果你想要一个更简单、幼稚的实现,至少看看Array.CopyTo(). 记住:我说的是“如果”。

于 2013-11-13T21:32:54.270 回答