Skip to content

Extension Method to Flatten Any Recursive Collection

Sometimes I wan’t to iterate all items in a recursive collection structure, e.g. the Controls hierarchy of Web Controls or Windows Forms Controls.

Instead of coding a “flatten” method for each collection type, I’ve written a small extension method Flatten that allows you to easily recurse any structure:

/// <summary> /// Flattens any recursive collection into a single list of all items. /// </summary> /// <typeparam name="T">Type of items in collection</typeparam> /// <param name="collection">Root collection of T items</param> /// <param name="recursor">Selector that returns the sub collection of a given item</param> /// <param name="predicate">Predicate to apply to each item before returning it</param> /// <returns>List of all items</returns> public static IList<T> Flatten<T>( this IEnumerable<T> collection, Func<T, IEnumerable<T>> recursor, Func<T, bool> predicate) { // Container for results var result = new System.Collections.Generic.List<T>(); // Queue of yet unprocessed collections var queue = new Queue<IEnumerable<T>>(); do { // Process current collection foreach (T control in collection) { queue.Enqueue(recursor(control)); if (predicate == null || predicate(control)) result.Add(control); } // Go to next or exit if done if (queue.Count > 0) collection = queue.Dequeue(); else return result; } while (true); }

The usage of it is simple:

IList<Control> allControls = Controls.Cast<Control>().Flatten(c => c.Controls.Cast<Control>(), null);

To avoid the ugly Cast<Control>() calls, you can define overloads of Flatten that works directly on ControlCollection. The reason why Cast is needed is that ControlCollection does not implement IEnumerable<Control>.


Executing a LINQ query asynchronously

Sometimes I want to execute a costly LINQ query in parallel with other tasks or maybe in parallel with other costly queries. This can be useful, e.g. if you need to load a lot of lookup data not related to eachother.

For that, I’ve made a small extension method:

public static Func<T[]> Async<T>(this IEnumerable<T> enumerable)
  System.Diagnostics.Debug.Assert(!(enumerable is ICollection),
  "Async does not work on arrays/lists/collections, only on true enumerables/queryables.");

  // Create delegate to exec async
  Func<IEnumerable<T>, T[]> work = e => e.ToArray();

  // Launch it
  IAsyncResult r = work.BeginInvoke(enumerable, null, null);

  // Return method that will block until completed and rethrow exceptions if any
  return () => work.EndInvoke(r);

The usage is then very simple as illustrated by the following code snippet:

// Define some expensive query
IQueryable<string> myExpensiveQuery = context.SystemLog.Where(l => l.Timestamp >= DateTime.Today.AddDays(-10));

// Start async processing
Func<string[]> waitForQueryData = myExpensiveQuery.Async();

// Do a lot of other work, e.g. other queries

// Need my query result now, so block until it's ready and get result
string[] myQueryResults = waitForQueryData();

If the query throws an exception you will get it in the waitForQueryData() call.