Visual Studio 2005 的穷人版 LINQ
一种在 .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()
等。它将所有调用转发到static
类Enumerable
。PoorMansLinq
并不包含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>
。