4

The question is: why does it use this code

  if (source is TSource[])
    return (IEnumerable<TResult>) new Enumerable.WhereSelectArrayIterator<TSource, TResult>((TSource[]) source, (Func<TSource, bool>) null, selector);
  if (source is List<TSource>)
    return (IEnumerable<TResult>) new Enumerable.WhereSelectListIterator<TSource, TResult>((List<TSource>) source, (Func<TSource, bool>) null, selector);
  else
    return (IEnumerable<TResult>) new Enumerable.WhereSelectEnumerableIterator<TSource, TResult>(source, (Func<TSource, bool>) null, selector);
}

instead of

  if (source is IList<TSource>)
    return (IEnumerable<TResult>) new Enumerable.WhereSelectIListIterator<TSource, TResult>((List<TSource>) source, (Func<TSource, bool>) null, selector);
  return (IEnumerable<TResult>) new Enumerable.WhereSelectEnumerableIterator<TSource, TResult>(source, (Func<TSource, bool>) null, selector);
}

i mean List<T> and T[] both implements IList<T> and they both has indexer and implements IEnumerable<T>, so they both can be iterated in the same singular manner, but now uses different iterators.

3
  • From where are you getting these code snippets? Commented Mar 14, 2014 at 4:36
  • I would imagine that under the hood when these iterators are used, LINQ can make reasonable optimizations - and may not be iterating them in the exact same manner. But without digging up LINQ source I can't prove this, just a strong hunch (ergo, a comment) Commented Mar 14, 2014 at 4:37
  • @payo referencesource.microsoft.com/#System.Core/System/Linq/… Commented Mar 14, 2014 at 8:46

1 Answer 1

5

It's simply an optimization that covers the extremely common cases of filtering an array or list.

  1. WhereSelectArrayIterator doesn't use the underlying enumerator of the array - it uses the indexer. From a performance standpoint, it's preferable to use the array-indexer directly than go through the IList<T> indexer or use the enumerator.

  2. WhereSelectListIterator does use the enumerator of the list, but because it "knows" the type of the List<TSource> enumerator to be the struct List<TSource>.Enumerator (which it can retrieve using the special GetEnumerator method on List<TSource> separate from the interface method), it avoids boxing the enumerator on the heap - which you would necessarily have to do if you used IEnumerator<TSource>.

  3. WhereSelectEnumerableIterator is the general case that uses the backing IEnumerator<TSource> of the source - it will work for all kinds of sequences, but without any special optimizations. If the enumerator happens to be a struct, tough luck - it will be boxed.

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

1 Comment

Yeah, i got it some minutes ago. So if the same idea comes comes to different people in the same time, probably it's right.

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.