Click here to Skip to main content
15,501,490 members
Articles / Programming Languages / C#
Posted 19 May 2008


34 bookmarked

Poor Man's LINQ in Visual Studio 2005

Rate me:
Please Sign up or sign in to vote.
4.53/5 (18 votes)
29 Oct 2010MIT3 min read
A way to use LINQ to Objects in C# 2.0 with .NET Framework 2.0


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
        // 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
        // 666
            .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


    .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:

    .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.


  • 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


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

Written By
Software Developer None
Canada Canada
Since I started programming when I was 11, I wrote the SNES emulator "SNEqr", the FastNav mapping component, the Enhanced C# programming language (in progress), the parser generator LLLPG, and LES, a syntax to help you start building programming languages, DSLs or build systems.

My overall focus is on the Language of your choice (Loyc) initiative, which is about investigating ways to improve interoperability between programming languages and putting more power in the hands of developers. I'm also seeking employment.

Comments and Discussions

QuestionGroup by Pin
NGUYEN HAI SON27-Oct-16 19:32
MemberNGUYEN HAI SON27-Oct-16 19:32 
AnswerRe: Group by Pin
Qwertie28-Oct-16 4:14
MemberQwertie28-Oct-16 4:14 
GeneralMy vote of 5 Pin
shrivallabh hampiholi26-Nov-12 20:41
Membershrivallabh hampiholi26-Nov-12 20:41 
QuestionBug in Join Pin
Member 85742615-Mar-12 11:39
MemberMember 85742615-Mar-12 11:39 
GeneralBug Pin
fapfip15-May-11 18:25
Memberfapfip15-May-11 18:25 
Generaluserfull Pin
Pranay Rana21-Dec-10 23:09
professionalPranay Rana21-Dec-10 23:09 
Generaluserfull Pin
Pranay Rana21-Dec-10 23:09
professionalPranay Rana21-Dec-10 23:09 
GeneralMy vote of 4 Pin
TweakBird29-Oct-10 0:49
MemberTweakBird29-Oct-10 0:49 
GeneralSee also my article Pin
Greg Olmstead27-Sep-10 11:42
MemberGreg Olmstead27-Sep-10 11:42 
GeneralGroup by Pin
Member 449449330-Mar-10 7:15
MemberMember 449449330-Mar-10 7:15 
QuestionSelect functionality not working? Pin
npetropoulosgr24-Jul-09 23:46
Membernpetropoulosgr24-Jul-09 23:46 
AnswerRe: Select functionality not working? Pin
Qwertie25-Jul-09 20:28
MemberQwertie25-Jul-09 20:28 
GeneralVS 2008 Express Pin
tagnarth26-May-08 14:01
Membertagnarth26-May-08 14:01 
GeneralSome limitations Pin
leppie21-May-08 3:57
Memberleppie21-May-08 3:57 
GeneralInteresting idea to backport Pin
Frohwalt Egerer21-May-08 2:14
MemberFrohwalt Egerer21-May-08 2:14 
GeneralAnother approach Pin
Sebastien Ros19-May-08 21:27
MemberSebastien Ros19-May-08 21:27 

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

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