C# 2008 学习笔记 - LINQ基础(二)- LINQ本质 (转)

http://www.cnblogs.com/sunrack/articles/1077173.html#1999991

LINQ查询符是用来调用System.Linq.Enumerable
定义的扩展函数的速记符号。

LINQ表达式在编译时,编译器会将查询操作符转换为对 System.Linq.Enumerable 类型中若干函数的调用(或者其他类型)。这些函数大部分都需要代理作为参数,特别的是,定义在
System.Core.dll 中的 泛型代理 Func<>,比如下面的几个Enumerable 成员函数:


// Overloaded versions of the Enumerable.Where<T>() method.
// Note the second parameter is of type System.Func<>.
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
System.Func
<TSource,int,bool> predicate)
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
System.Func
<TSource,bool> predicate)

Func<>的定义:其中最后一个类型参数TResult代表返回类型


// The various formats of the Func<> delegate.
public delegate TResult Func<T0,T1,T2,T3,TResult>(
T0 arg0, T1 arg1, T2 arg2, T3 arg3)
public delegate TResult Func<T0,T1,T2,TResult>(T0 arg0, T1 arg1, T2 arg2)
public delegate TResult Func<T0,T1,TResult>(T0 arg0, T1 arg1)
public delegate TResult Func<T0,TResult>(T0 arg0)
public delegate TResult Func<TResult>()


由于 System.Linq.Enumerable
的很多成员函数需要代理作为参数,因此,在调用时,我们可以用三种方式实现:

1、定义新的代理类型,并定义相应的处理函数
2、使用匿名函数
3、使用Lambda表达式

一、使用查询操作符定义查询表达式

这是最直接和简洁的方式,也是推荐方式:


static void QueryStringWithOperators()
{
Console.WriteLine(
"***** Using Query Operators *****");
string[] currentVideoGames = {"Morrowind", "BioShock",
"Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
// Build a query expression using query operators.
var subset = from g in currentVideoGames
where g.Length > 6 orderby g select g;
// Print out the results.
foreach (var s in subset)
Console.WriteLine(
"Item: {0}", s);
}

二、使用Enumerable类型函数和Lambda表达式定义查询表达式

直接使用Enumerable扩展函数


static void QueryStringsWithEnumerableAndLambdas()
{
Console.WriteLine(
"***** Using Enumerable / Lambda Expressions *****");
string[] currentVideoGames = {"Morrowind", "BioShock",
"Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
// Build a query expression using extension methods
// granted to the Array via the Enumerable type.
var subset = currentVideoGames.Where(game => game.Length > 6)
.OrderBy(game
=> game).Select(game => game);
// Print out the results.
foreach (var game in subset)
Console.WriteLine(
"Item: {0}", game);
Console.WriteLine();
}

由于Enumerable扩展了数组类型,所以这里可以直接在 string类型的数组(string[]) 上调用泛型函数Where()。Enumerable.Where<T>()函数使用了System.Func<T0, TResult>。第一个参数是实现了IEnumerable<T>接口的待处理数据(上例中是string类型的数组对象),第二个参数是用来处理该数据的代理。

Enumerable.Where<T>()的返回类型是隐式的,实际上是OrderedEnumerable类型,在这个返回对象上,可以调用泛型函数 OrderBy<T,K>(),它也需要 Func<T,
K>
代理作为参数,最后,在Lambda表达式的返回结果上选择所有元素时,再次调用了Func<T,
K>


由于扩展函数的特殊性,既可以在被扩展的类型的实例上调用,也可以在定义该函数的静态类中调用,所以,上例可以写为:


var subset = Enumerable.Where(currentVideoGames, game => game.Length > 6)
.OrderBy(game
=> game).Select(game => game);

可以看出,使用Enumberable类型的函数来定义LINQ查询表达式要比直接使用LINQ查询符繁琐的多,并且需要书写Lambda表达式。


三、使用Enumerable类型函数和匿名方法定义查询表达式


static void QueryStringsWithAnonymousMethods()
{
Console.WriteLine(
"***** Using Anonymous Methods *****");
string[] currentVideoGames = {"Morrowind", "BioShock",
"Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
// Build the necessary Func<> delegates using anonymous methods.
Func<string, bool> searchFilter =
delegate(string game) { return game.Length > 6; };
Func
<string, string> itemToProcess = delegate(string s) { return s; };
// Pass the delegates into the methods of Enumerable.
var subset = currentVideoGames.Where(searchFilter)
.OrderBy(itemToProcess).Select(itemToProcess);
// Print out the results.
foreach (var game in subset)
Console.WriteLine(
"Item: {0}", game);
Console.WriteLine();
}

可以看出这种方式更加繁琐,因为我们自己定义了Where(), OrderBy(), and
Select()等函数需要的
Func<>代理。

三、使用Enumerable类型函数和代理定义查询表达式

最繁琐的方式就是,不使用Lambda表达式和匿名函数,为每个FUN<>类型手动定义代理。


class VeryComplexQueryExpression
{
public static void QueryStringsWithRawDelegates()
{
Console.WriteLine(
"***** Using Raw Delegates *****");
string[] currentVideoGames = {"Morrowind", "BioShock",
"Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
// Build the necessary Func<> delegates using anonymous methods.
Func<string, bool> searchFilter = new Func<string, bool>(Filter);
Func
<string, string> itemToProcess = new Func<string,string>(ProcessItem);
// Pass the delegates into the methods of Enumerable.
var subset = currentVideoGames
.Where(searchFilter).OrderBy(itemToProcess).Select(itemToProcess);
// Print out the results.
foreach (var game in subset)
Console.WriteLine(
"Item: {0}", game);
Console.WriteLine();
}
// Delegate targets.
public static bool Filter(string s) {return s.Length > 6;}
public static string ProcessItem(string s) { return s; }
}

四、LINQ本质总结

1、使用LINQ查询符来创建LINQ查询表达式
2、LINQ查询符是用来调用System.Linq.Enumerable
定义的扩展函数的速记符号。
3、大多数Enumerable 类型的函数需要代理(特别的如Func<>
)作为参数
4、C#2008种,任何需要代理作为参数的函数,都可以改为用Lambda表达式作为参数。
5、Lambda表达式仅仅是匿名函数的掩饰,可以大大提高可读性
6、匿名函数是手动定义代理类型并定义相应的处理函数的速记符号。
posted @ 2011-06-13 22:16  董雨  阅读(234)  评论(0编辑  收藏  举报