Mobile Software Engineering

2009-02-06 by tamberg

Implementing LINQ on the .NET Micro Framework

The .NET Micro Framework, a variant of .NET radically scaled down for embedded systems, does not include the System.Linq namespace and does not provide any LINQ functionality. Because its implementation is based on generics, LINQ requires version 2.0 of the CLR. The Micro Framework on the other hand is restricted to the CLI, a standardized specification of Microsoft's CLR 1.0.

Fortunately, the other relevant language features such as lambda expressions, extension methods and list comprehension can all be seen as syntactic sugar. Introduced with C# 3.0 - and due to the genius of Anders Hejlsberg - those features can be compiled to IL instructions already implemented by any CLI-compliant virtual machine. And, as Marc Frei and Cuno Pfister prove with the following code, the lack of generics barely affects the undeniable elegance of LINQ.

// Linq.cs

using System.Collections;
using Microsoft.SPOT;

namespace System.Runtime.CompilerServices {
  [AttributeUsageAttribute(
    AttributeTargets.Assembly
    | AttributeTargets.Class
    | AttributeTargets.Method)]
  sealed class ExtensionAttribute: Attribute {}
}

delegate bool Predicate (object o);

sealed class Enumerator: IEnumerator {
  IEnumerator e;
  Predicate p;

  internal Enumerator (IEnumerator e, Predicate p) {
    this.e = e;
    this.p = p;
  }

  object IEnumerator.Current {
    get { return e.Current; }
  }

  void IEnumerator.Reset () {
    e.Reset();
  }

  bool IEnumerator.MoveNext () {
    var b = e.MoveNext();
    while (b && !p(e.Current)) {
      b = e.MoveNext();
    }
    return b;
  }
}

sealed class Filter: IEnumerable {
  IEnumerable e;
  Predicate p;

  internal Filter (IEnumerable e, Predicate p) {
    this.e = e;
    this.p = p;
  }

  IEnumerator IEnumerable.GetEnumerator () {
    return new Enumerator(e.GetEnumerator(), p);
  }
}

static class Program {
  static int Count (this IEnumerable e) {
    var n = 0;
    foreach (var o in e) {
      n++;
    }
    return n;
  }

  static IEnumerable Where (this IEnumerable e, Predicate p) {
    return new Filter(e, p);
  }

  static void Main () {
    var a = new int[] {1, 2, 3, 4, 6, 8, 9, 9, 9};
    var n = a.Where(v => (int) v % 2 == 0).Count();
    var m = (from v in a where (int) v % 2 == 0 select v).Count();
    Debug.Print(n + " " + m);
  }
}