So how do we convert a fluent string of methods taking and returning instances of IEnumerable's into the equivalent imperative version?

Let's review a simple lambda that highlights all the necessary components of the conversion algorithm:
(int[] source) => source.Select(i => i*2).ToList();

Its imperative version would then look like this (decompiled using ILSpy):
public static List<int> Recompiled(int[] source)
	if (source == null)
		throw new ArgumentNullException("source");
	List<int> list = new List<int>();
	int num = source.Length;
	for (int i = 0; i < num; i++)
		int num2 = source[i];
		int item = num2 * 2;
	return list;

  • The iteration - LINQ methods always operate on IEnumerable<T> which is both very flexible and slowing. FtLinq can operate on multiple types of input sequences - arrays, List<T>, IList<T>, etc. When compiling a LINQ lambda FtLinq chooses the optimal algorithm to iterate over the source sequence. If it's an array or list, then the iteration is done (as above) in a for loop. TODO: explain better ->If the sequence object has a method GetEnumerator() that returns a concrete enumerator implementation (as opposed to an abstract IEnumerator<T>) then the iteration is done using a construction equivalent to the C# foreach statement. If the enumerator is a value type or a sealed type, then that might save us virtual calls.
  • The aggregation - to produce side-effects, the LINQ query must first be enumerated. This happens by calling aggregation methods on the LINQ expression - e.g. ToArray(), ToList(), Sum(), Average(), etc.

Last edited Dec 24, 2012 at 8:12 AM by tailsu, version 1


No comments yet.