Som du ser försöker .Count() downcasta till rätt typ. Polymorfism i den vanliga betydelsen är inte möjligt på extensionmetoder eftersom dessa är statiska och därför inte overrideable.
När du kör Where() på en array får du tillbaka en WhereArrayIterator<Int32> som även den saknar definierad längd. Det är denna du sedan skickar in i qsort igen. För att få ut längden av en WhereArrayIterator behöver man itererera, se http://stackoverflow.com/questions/7269498/ienumerable-vs-ili...
Inser exakt vad du säger och har nu justerat black-box-mätningen så den skapar en WhereArrayIterator(). Det är faktiskt värre än man kunde ana, visar sig att tiden det tar att anropa Count() är O(N) men N referera inte till storleken på resultatet från Where() utan från indata. WTF! Det betyder att man inte kan komma runt prestandaproblemen genom att se till att lägga de filter som tar bort många element tidigt i pipeline:en.
Skulle hävda att dessa saker gör LINQ broken-by-implementation för alla former av icke-trivial manipulation av även rätt små data-set (qsort havererar redan vid 10k element). Att anropa Count() en enda gång på en WhereArrayIterator() med 1M element tar 10ms på min laptop (Sandy Bridge på 3.1GHz). 10ms är eoner av tid, man hinner t.ex. sortera 100k element på den tiden med QuickSort/MergeSort om man skippar LINQ...
Visst kan man hävda att jag använder LINQ på ett felaktigt sätt, men faktum kvarstår att jag kan skriva exakt samma logik i Clojure, Erlang (ska lägga till exempel i detta språk) och även i C++ via biblioteket CppLinq och få något som är minst 1000 gånger snabbare. Så kritiken mot att LINQ är slött är definitivt inte obefogad, man kan inte heller hävda att idéerna bakom LINQ är broken-by-design då de bevisligen fungerar och är effektiva i andra implementationer.
Med CppLinq kan man implementera QuickSort t.ex. så här i C++
vector<int> quick_sort(const vector<int>& v)
{
// detta är naturligtvis onödigt, kan ju köra .size() på 'v', men vill var så nära C#/LINQ varianten som möjligt
auto c = from(v);
if (c >> count() <= 1)
return v;
auto pivot = c >> first_or_default();
auto rest = c >> skip(1);
auto lo = quick_sort(rest >> where([pivot](int e) { return e <= pivot; }) >> to_vector());
lo.push_back(pivot);
auto hi = quick_sort(rest >> where([pivot](int e) { return e > pivot; }) >> to_vector());
copy(begin(hi), end(hi), back_inserter(lo));
return lo;
}
och hastigheten är ungefär 3-4 gånger långsammare än att jobbar direkt med råa arrayer
sz 100000 limit 10000
Quick sort: 0.03
sz 100000 limit 1000000000
Quick sort: 0.03
sz 1000000 limit 10000
Quick sort: 0.53
sz 1000000 limit 1000000000
Quick sort: 0.35
sz 10000000 limit 10000
Quick sort: 21.42
sz 10000000 limit 1000000000
Quick sort: 3.96
Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer