Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

Poor Man's LINQ in Visual Studio 2005

Rate me:
Please Sign up or sign in to vote.
4.53/5 (18 votes)
28 Oct 2010MIT3 min read 80.8K   619   34   16
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.

C#
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:

C#
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:

C#
from x in numbers
where x > 300
select x

becomes:

C#
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:

C#
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


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 18:32
NGUYEN HAI SON27-Oct-16 18:32 
AnswerRe: Group by Pin
Qwertie28-Oct-16 3:14
Qwertie28-Oct-16 3:14 
GeneralMy vote of 5 Pin
shrivallabh hampiholi26-Nov-12 19:41
shrivallabh hampiholi26-Nov-12 19:41 
QuestionBug in Join Pin
Member 85742615-Mar-12 10:39
Member 85742615-Mar-12 10:39 
GeneralBug Pin
fapfip15-May-11 17:25
fapfip15-May-11 17:25 
Generaluserfull Pin
Pranay Rana21-Dec-10 22:09
professionalPranay Rana21-Dec-10 22:09 
Generaluserfull Pin
Pranay Rana21-Dec-10 22:09
professionalPranay Rana21-Dec-10 22:09 
GeneralMy vote of 4 Pin
TweakBird28-Oct-10 23:49
TweakBird28-Oct-10 23:49 
GeneralSee also my article Pin
Greg Olmstead27-Sep-10 10:42
Greg Olmstead27-Sep-10 10:42 
GeneralGroup by Pin
Member 449449330-Mar-10 6:15
Member 449449330-Mar-10 6:15 
QuestionSelect functionality not working? Pin
npetropoulosgr24-Jul-09 22:46
npetropoulosgr24-Jul-09 22:46 
AnswerRe: Select functionality not working? Pin
Qwertie25-Jul-09 19:28
Qwertie25-Jul-09 19:28 
GeneralVS 2008 Express Pin
tagnarth26-May-08 13:01
tagnarth26-May-08 13:01 
GeneralSome limitations Pin
leppie21-May-08 2:57
leppie21-May-08 2:57 
GeneralInteresting idea to backport Pin
User 35433221-May-08 1:14
User 35433221-May-08 1:14 
GeneralAnother approach Pin
Sebastien Ros19-May-08 20:27
Sebastien Ros19-May-08 20: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.