Posterous theme by Cory Watilo

Using LINQ on objects which implements IEnumerable

In order for LINQ to be able to do its magic it has to rely on some help. This help is provided in the form of a set of Extension Methods on the IEnumerable<T> and IQueryable<T> interfaces, if the input to a query expression does not support one of these interfaces then your code won't compile.


There are a lot of collection classes in the framework that predates the introduction of the generic interfaces and as such you are destined not to be able to access then with the help of LINQ query expressions until Microsoft updates the classes (don’t hold your breath!), or are you? What if there was an easy way to disguise these old (or any class which only implements IEnumerable but not IEnumerable<T>) classes as a IEnumerable<T>?

Presenting the LinqWrapper<T> class

So a really easy way to enable you to execute LINQ query expressions on classes, which only implements the IEnumerable interface and not the IEnumerable<T> interface, is to provide a wrapper around it.


Basically what I did was to create a class, which implements the IEnumerable<T> interface and accepts a single constructor parameter, a (you guessed it!) IEnumerable object. The only purpose the class has is to wrap the provided object in a strongly-typed enumerator which enables access to the LINQ extension methods needed to execute LINQ query expressions against it.


1:  using System.Collections;
2:  using System.Collections.Generic;
3:   
4:  /// <summary>
5:  /// Provides a strongly types <see cref="IEnumerable{T}"/> wrapper
6:  /// around any class which implements the <see cref="IEnumerable"/>
7:  /// interface.
8:  /// </summary>
9:  /// <typeparam name="T">The type of the object to wrap.</typeparam>
10:  public class LinqWrapper<T> : IEnumerable<T>
11:  {
12:      /// <summary>
13:      /// Initializes a new instance of the <see cref="LinqWrapper"/>
14:      /// class.
15:      /// </summary>
16:      /// <param name="source">An object that implements the
17:      /// <see cref="IEnumerable"/> interface.</param>
18:      public LinqWrapper(IEnumerable source)
19:      {
20:          this.Source = source;
21:      }
22:   
23:      /// <summary>
24:      /// Gets or sets the source object.
25:      /// </summary>
26:      /// <value>
27:      /// An object which implements the
28:      /// <see cref="IEnumerable"/> interface
29:      /// </value>
30:      public IEnumerable Source { get; set; }
31:   
32:      /// <summary>
33:      /// Enables strongly-typed enumeration on the source.
34:      /// </summary>
35:      /// <returns>An <see cref="IEnumerator{T}"/> object.</returns>
36:      IEnumerator<T> IEnumerable<T>.GetEnumerator()
37:      {
38:          foreach (T item in this.Source)
39:          {
40:              yield return item;
41:          }
42:      }
43:   
44:      /// <summary>
45:      /// Enables enumeration on the source.
46:      /// </summary>
47:      /// <returns>An <see cref="IEnumerator"/> object.</returns>
48:      IEnumerator IEnumerable.GetEnumerator()
49:      {
50:          IEnumerable<T> iterator =
51:              this as IEnumerable<T>;
52:          return iterator.GetEnumerator();
53:      }
54:  }

The only thing left to do is to try it out! Let’s start of by creating a data table with some columns and add some rows into it. I decided to create a rather silly little employee record table which only contains an id, a name and an age.


Note! This is a basic example to illustrate how the wrapper works and I didn't want to implement my own IEnumerable class. For production code you may as well use the AsEnumerable extention method for a DataTable provided ny the DataTableExtensions class in the System.Linq namespace.


1:  // Setup a data table with some rows, to enable
2:  // use to perform a LINQ query on it.
3:   
4:  DataTable values =
5:      new DataTable("valuesTable");
6:   
7:  values.Columns.AddRange(
8:      new DataColumn[]
9:      {
10:          new DataColumn("ID", typeof(int)),
11:          new DataColumn("Name", typeof(string)),
12:          new DataColumn("Age", typeof(int))
13:      }
14:  );
15:   
16:  values.Rows.Add(new object[] { 1, "Bob", 28 });
17:  values.Rows.Add(new object[] { 2, "Alice", 35 });
18:  values.Rows.Add(new object[] { 3, "Sally", 19 });
19:  values.Rows.Add(new object[] { 4, "Frank", 46 });

Pretty straight forward, no need to bend over backwards to give the LinqWrapper<T> class some exercise. Now that we have a data source we have all that we need in order to try it out, so let’s do just that.


1:  // Select all employees that are younger than
2:  // 30 years old.
3:   
4:  var employees =
5:      from e in new LinqWrapper<DataRow>(values.Rows)
6:      where (int)e["Age"] < 30
7:      select e;

The LINQ query expression above wraps the Rows parameter (which is of the type DataRowCollection and implements the IEnumerable interface) and selects all the employees which are younger than 30 years old. Let’s see what we got!


1:  // Output the employees which were seleced
2:  // with the help of a LINQ query
3:   
4:  foreach (var employee in employees)
5:  {
6:      Console.WriteLine("{0} - {1} ({2})",
7:          employee["ID"], employee["Name"], employee["Age"]);
8:  }

The above code will provide the following output


1 - Bob (28)
3 - Sally (19)


Hey what do you know!? Just what we wanted! So there you have it, a simple wrapper class which enables you to execute LINQ queries on collections which doesn’t natively support them out of the box.


You can download the full source code at my codeplex page

| Viewed
times
Filed under: