LINQ missed optimization (and the fun of interfaces)

LINQ is a bit of an interesting beast, it makes certain things easier, but it also performs so much worse in many scenarios.

I had assumed that LINQ internally would have a decent amount of optimizations, some of its operations will perform better if you know that the incoming collection is ICollection and can thus get the count, for instance. ToArray for instance will use the count property, and CopyTo from ICollection to improve performance. (Although it then goes and copies the result array into another identical array…)

However, say you have a List and you use the Select operation on it, the internally constructed deferred execution object implements IEnumerable and not ICollection. This is despite the fact the count is still known, since the select operation is just a conversion of elements. A CopyTo method could be written as well. Things start to get stretched once we hit the Contains method though (as needed for the interface, not required for LINQ optimization…), which would have to enumerate the entire data set, applying the select conversion to each element… and what does that mean anyway?

The net result is that something like list.Select(a=>a.ToString()).ToArray() actually internally has to create an array out of an IEnumerable with no count information… It does this using repeated copying to size doubling arrays, and then trimming the final array by copying into a new array of the right size.
All that performance loss to avoid a couple of lines of code…