65.9K
CodeProject 正在变化。 阅读更多。
Home

Visual Studio 2005 的穷人版 LINQ

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.53/5 (17投票s)

2008 年 5 月 19 日

MIT

3分钟阅读

viewsIcon

86315

downloadIcon

634

一种在 .NET Framework 2.0 和 C# 2.0 中使用 LINQ to Objects 的方法

引言

C# 3.0 中的语言集成查询 (LINQ) 使用起来非常令人愉悦。一旦尝试,你就会爱不释手。

但是,由于各种原因,我们中的一些人仍在使用 Visual Studio 2005。就我而言,我不想为升级到 VS2008 Pro 付款 550 美元,但我也不想通过切换到 Visual C# Express Edition 或 SharpDevelop 而丢失宏和代码图之类的功能。因此,我想出了一个在 C# 2.0 中使用 LINQ to Objects 的方法。

注意:如果你只能使用 .NET Framework 2.0,但你正在使用 C# 3.0 或 Visual Studio 2008,则不需要本文中的代码。只需使用 LinqBridge

Using the Code

这是一些简单的 C# 3.0 LINQ 代码。此代码包含一个查询和对System.Linq.Enumerable类中扩展方法的几次调用。当然,由于它们是扩展方法,因此代码实际上并没有提及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());
    }
}

现在,这是 C# 2.0 中的等效代码,它利用了我的PoorMansLinq类。

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);
    }
}

看看第一个WriteLine语句:它不是words.Take(3).ToArray(),而是Linq(words).Take(3).ToArray()Linq()是一个辅助函数,它只是将一个IEnumerable对象包装在一个PoorMansLinq对象中;它本可以写成new PoorMansLinq<string>(words).Take(3).ToArray()

PoorMansLinq提供了大部分 LINQ 功能,例如Where()OrderBy()等。它将所有调用转发到staticEnumerablePoorMansLinq并不包含Enumerable的所有功能。

  • 它不包含诸如Empty()Range(first, last)之类的静态方法,这些方法不是扩展方法。
  • 它不包含AsEnumerable(),如果没有扩展方法功能,这毫无意义。
  • 它不能包含特定类型T的特化,例如Average<double>()Sum<int>(),因为据我所知,在 C# 2.0 中没有办法使用泛型来做到这一点。因此,为了计算整数、双精度数或十进制数的 Sum、Average、Min 或 Max,你需要直接调用Enumerable中的方法。

PoorMansLinq还包括Sorted(),它是OrderBy(x => x)的快捷方式,你可以在第二个WriteLine语句中看到它。在 C# 2.0 中,你必须编写OrderBy(delegate(string x) { return x; }),这很麻烦。

正如我提到的,你不能使用Linq(numbers).Sum()语法来对数字求和,因此第三个WriteLine使用Enumerable.Sum(numbers)代替。

第四个WriteLine演示了如何转换简单的查询。

from x in numbers
where x > 300
select x

变成

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

我省略了Select子句,在这种情况下不需要它。以下是包含冗余Select子句的样子。

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

请参阅这篇文章,了解 C# 3.0 将 LINQ 查询转换为“普通”C# 3.0 代码的方式。然后,本文中的信息应该足以将其转换为 C# 2.0。

我是怎么做到的?

我首先从开源项目Mono中提取了核心 LINQ to Objects 代码。然后,我编写了PoorMansLinq<T>,这是一个围绕IEnumerable<T>的包装器,它提供了扩展方法。

历史

  • 2008 年 5 月 19 日:初始发布
  • 2010 年 10 月 27 日:已将PoorMansLinq<T>中返回IEnumerable<T>的一些函数更正为返回PoorMansLinq<T>
© . All rights reserved.