Click here to Skip to main content
Click here to Skip to main content

Poor Man's LINQ in Visual Studio 2005

, 28 Oct 2010
Rate this:
Please Sign up or sign in to vote.
A way to use LINQ to Objects in C# 2.0 with .NET Framework 2.0

Introduction

Language INtegrated Query in C# 3.0 is pure joy to use. Once you try it, you don't want to stop.

But a few of us, for whatever reason, are still using Visual Studio 2005. In my case, I didn't want to pay $550 for the upgrade to VS2008 Pro, but I didn't want to lose features like Macros and Code Diagrams by switching to Visual C# Express Edition or SharpDevelop. So, I came up with a way I could use LINQ-to-Objects in C# 2.0.

Note: If you are stuck with .NET Framework 2.0, but you are using C# 3.0 or Visual Studio 2008, you don't need the code in this article. Just use LinqBridge.

Using the Code

Here is some simple C# 3.0 LINQ code. This code contains a query and several calls to extension methods in the System.Linq.Enumerable class. Of course, since they are extension methods, the code doesn't actually mention Enumerable.

using System;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        string[] words = new string[] { 
            "Pies", "Are", "Good", 
            "In", "Lovely", "Apples" };
        // Pies Are Good
        Console.WriteLine(string.Join(" ", words.Take(3).ToArray()));
        // Apples Are Good In Lovely Pies
        Console.WriteLine(string.Join(" ", words.OrderBy(x => x).ToArray()));

        int[] numbers = new int[] { 4, 95, 309, 357, 233, 2 };
        // 1000
        Console.WriteLine(numbers.Sum());
        // 666
        Console.WriteLine((from x in numbers where x > 300 select x).Sum());
    }
}

Now, here is the equivalent code in C# 2.0, taking advantage of my PoorMansLinq class:

using System;
using System.Collections.Generic;
using Compatibility.Linq;

class Program
{
    public static void Main(string[] args)
    {
        string[] words = new string[] {
            "Pies", "Are", "Good", "In", 
            "Lovely", "Apples" };
        // Pies Are Good
        Console.WriteLine(string.Join(" ", Linq(words).Take(3).ToArray()));
        // Apples Are Good In Lovely Pies
        Console.WriteLine(string.Join(" ", Linq(words).Sorted().ToArray()));

        int[] numbers = new int[] { 4, 95, 309, 357, 233, 2 };
        // 1000
        Console.WriteLine(Enumerable.Sum(numbers));
        // 666
        Console.WriteLine(Enumerable.Sum(Linq(numbers)
            .Where(delegate(int x) { return x > 300; })));
    }
    static PoorMansLinq<T> Linq<T>(IEnumerable<T> source)
    {
        return new PoorMansLinq<T>(source);
    }
}

Look at the first WriteLine statement: instead of words.Take(3).ToArray(), it reads Linq(words).Take(3).ToArray(). Linq() is a helper function that simply wraps an IEnumerable object in a PoorMansLinq object; it could have been written new PoorMansLinq<string>(words).Take(3).ToArray() instead.

PoorMansLinq provides most of the LINQ functionality such as Where(), OrderBy(), etc. It forwards all the calls to the static class Enumerable. PoorMansLinq does not include all the functionality of Enumerable:

  • It does not include static methods such as Empty() and Range(first, last) that are not extension methods.
  • It doesn't include AsEnumerable(), which makes no sense without the extension methods feature.
  • It cannot include specializations for specific kinds of T, such as Average<double>() and Sum<int>(), because as far as I know, there is no way to do it with Generics in C# 2.0. Therefore, in order to compute the Sum, Average, Min, or Max of integers, doubles, or decimals, you need to call the method in Enumerable directly.

PoorMansLinq also includes Sorted(), which is a shortcut for OrderBy(x => x) that you see in the second WriteLine statement. In C# 2.0, you would have to write OrderBy(delegate(string x) { return x; }), which is cumbersome.

As I mentioned, you can't Sum numbers using the Linq(numbers).Sum() syntax, so the third WriteLine uses Enumerable.Sum(numbers) instead.

The forth WriteLine demonstrates how a simple query is translated:

from x in numbers
where x > 300
select x

becomes:

Linq(numbers)
    .Where(delegate(int x) { return x > 300; })

I omitted the Select clause, which is not needed in this case. Here's how it looks with the redundant Select clause:

Linq(numbers)
    .Where(delegate(int x) { return x > 300; })
    .Select(delegate(int x) { return x; })

See this article for an introduction to the way C# 3.0 translates LINQ queries to "plain" C# 3.0. Then, the information in this article should be enough to turn it into C# 2.0.

How Did I Do It?

I started by extracting the core LINQ-to-objects code from Mono, which is open source. Then, I wrote PoorMansLinq<T>, a wrapper around IEnumerable<T> that provides the extension methods.

History

  • May 19, 2008: Initial release
  • October 27, 2010: Some functions in PoorMansLinq<T> that returned IEnumerable<T> have been corrected to return PoorMansLinq<T> instead

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Qwertie
Software Developer Trapeze Software, Inc.
Canada Canada
Since I started programming when I was 11, I wrote the SNES emulator "SNEqr", the FastNav mapping component, and LLLPG, among other things. Now I'm old.
 
In my spare time I'm developing a system called Loyc (Language of your choice), which will include an enhanced C# compiler. Many programs have an add-in architecture; why not your programming language? I'm also looking for a life partner. Oh hi future wife! Wazzap.

Comments and Discussions

 
GeneralMy vote of 5 Pinmembershrivallabh hampiholi26-Nov-12 19:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 29 Oct 2010
Article Copyright 2008 by Qwertie
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid