1

Ok, maybe I'm just lazy but this might be a cool question to have on the interwebs.

I know that Buffer.BlockCopy(...) is faster than Array.Copy(...) when working with byte[]. I was about to write a CloneBuffer helper that would create an array the same size as a source array then copy the source array into it using Buffer.BlockCopy(...) when I instead wrote:

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

    // Start async send here and return immediately
}

Does anyone know if the ToArray() method special-cased for byte[] or if this is going to be slower than BlockCopy?

3
  • I would doubt it, but you can look at the source code and see for yourself if you're curious. Commented Nov 13, 2013 at 21:24
  • Why do you feel the need to wrap Buffer.BlockCopy in the first place? Commented Nov 13, 2013 at 21:30
  • @EdS. In quite a few places in my code I new up a new byte[] of the length of the source, then copy the source to the new array. It's just a DRY function so I don't have to write the 3 lines of code everywhere I need to copy a buffer. Commented Nov 13, 2013 at 21:36

2 Answers 2

7

You can look into the Microsoft .NET assemblies using a reflector program, such as ILSpy.

This tells me that the implementation of System.Linq.Enumerable::ToArray() is:

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

And the constructor of the internal struct Buffer<T> does:

  • If the source enumerable implements ICollection<T>, then:
    • allocate an array of Count elements, and
    • use CopyTo() to copy the collection into the array.
  • Otherwise:
    • allocate an array of 4 elements, and
    • start enumerating the IEnumerable, storing each value in the array.
    • Is the array too small?
      • Create a new array that has twice the size of the old one,
      • and copy the old array's content into the new one,
      • then use the new array instead, and continue.

And Buffer<T>.ToArray() simply returns the inner array if its size matches the number of elements in it; otherwise copies the inner array to a new array with the exact size.

Note that this Buffer<T> class is internal and not related to the Buffer class you mentioned.

All copying is done using Array.Copy().

So, to conclude: all copying is done using Array.Copy() and there is no optimization for byte arrays. But I don't know whether it is slower than Buffer.BlockCopy(). The only way to know is to measure.

Sign up to request clarification or add additional context in comments.

1 Comment

This is great, thanks for the info. If I remember, the Array.Copy() wasn't that much slower, so this will probably work fine for my needs.
0

Yes, it is going to be slower.

When you look at the documentation for the System.Array methods, there is no definition for System.Array.ToArray(). In fact, looking at the inheritance/interface tree, it's all the way we have to go back all the way to [IEnumerable.ToArray()][2] before we find this method. Since this was implemented with only the features of IEnumerable to work with, it can't know the size of the resulting array when it begins executing. Instead, it uses a doubling algorithm to build up the array as it runs. So you might end up creating and throwing away several arrays over the course of making the copy, and copying those initial items several time in the course of destroying/recreating each intermediate buffer.

If you want a simpler, naive implementation, at least look at Array.CopyTo(). And remember: I said, "If".

1 Comment

This is not correct. Why do you assume it can only be implemented with the features of IEnumerable? It does know the size of the resulting array when it begins executing, if the enumerable implements ICollection<T>. That's an optimization.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.