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、匿名函数是手动定义代理类型并定义相应的处理函数的速记符号。