------Linq方法语法和Lambda表达式
2.1λ表达式
Lambda表达式用来实现一个匿名方法,其语法为:
(参数列表)=>语句或语句块
这是一个简单的Lambda表达式:n=>n<1000;
运算符“=>”称为λ表达式。这个表达式定义了一个方法(函数),其参数是n,如果n小于1000,该方法就返回ture,否则返回false。该方法是一个没有名称的匿名方法,仅在把λ表达式传给Linq方法时使用。
2.2λ表达式在Linq中的使用
用Linq完成同一任务有多种方式,但通常需要通过编程来实现。如上一章内容是使用Linq查询语法编写的。本章内容将重点介绍Linq的方法语法。
Linq拥有一系列扩展方法,用于集合、数组、查询结果等对象,不在需要from…where…select子句。回顾上一章内容的示例:
varresult=fromninnameswheren.StartsWith("s")selectn;
现在可以用方法语法来实现:
varresult=names.Where(n=>n.StartsWith("s"));
C#编译器把λ表达式编译成一个匿名方法,where()在names数组中的每一个元素上执行这个方法。如果λ表达式给某个元素返回true,该元素就包含在Where()返回的结果集中。
查询语法是Linq中编写查询的首选方式,但是一定要基本了解方法语法,因为一些Ling功能不能通过查询语法来使用,或者说使用方法语法比较简单。
2.2.1用方法语法排序
对刚才的查询结果排序可以使用如下语句:
varresult=names.OrderBy(n=>n).Where(n=>n.StartsWith("s"));
或者:
varresult=names.Where(n=>n.StartsWith("s")).OrderBy(n=>n);
方法调用的顺序不是固定的,只要Linq方法返回值为IEnumerable类型即可,可以按照容易理解的方式来使用。此规则适合于以后讲到的其他方法。
OrderBy()方法需要传入一个λ表达式用来告诉它用于排序的方法是什么,我们传送了最简单的λ表达式n=>n,因为只需要按照元素本身排序。还可以向上一章所讲那样按照最后一个字母进行排序,传给OrderBy()方法一个这样的表达式:n=>n.Substring(n.Length-1)
为了给元素逆序排序,可以调用OrderByDescending()方法,使用方法和OrderBy()相同。
2.2.2投射的方法语法
投射查询的方法语法版本是通过把Linq方法Select()的调用关联到我们调用的其他Linq方法上来实现的。例如要实现上一章示例五的功能,代码如下:
varresult=list.Where(stu=>stu.Age==18).Select(stu=>new{stu.Name,stu.Age,stu.Class});
Select()方法用于方法语法的投射。
常见错误:
varresult=list.Select(stu=>newstu.Name,stu.Age,
stu.Class}).Where(stu=>stu.Sex==’男’);
虽说方法的调用顺序不固定,但根据查询的特性,不适用与上面的查询。因为Sex属性并不包含在Select()投射创建的匿名类型(stu.Name,stu.Age,stu.Class)中,所以上述代码会在Where()方法上得到一个编译错误---匿名类型不包含Sex的定义。改成如下写法是正确的。
varresult=list.Select(stu=>newstu.Name,stu.Age,
stu.Class}).Where(stu=>stu.Class==’50’);
2.2.3Any和All
我们常常需要的另一类查询是确定数据是否满足某个条件,或者确保所有的数据都满足某个条件。例如,需要确定某个产品是否没有货了(库存为0)。
Linq提供了两个布尔方法:Any()和All(),它们可以快速确定对于数据而言,某个条件是true还是false。如下面示例所示:
boolanyStu=list.Any(stu=>stu.Sex=="男"); if(anyStu) { Console.WriteLine("学员中有男同学"); } else { Console.WriteLine("学员中没有男同学"); } boolallStu=list.All(stu=>stu.Sex=="男"); if(allStu) { Console.WriteLine("学员中全部是男同学"); } else { Console.WriteLine("学员中不全是男同学"); } |
运行结果:
2.2.4ThenBy-----多级排序
使用方法语法进行多级排序时,后台的操作比较复杂,它使用了ThenBy()和OrderBy()方法。示例代码如下:
varresult=list.OrderBy(stu=>stu.Class) .ThenBy(stu=>stu.Age) .ThenBy(stu=>stu.Name) .Select(stu=>new{stu.Name,stu.Age,stu.Class}); |
多字段列表可以用在查询语法的OrderBy子句中。但在方法语法中第一项排序字段必须使用OrderBy()方法,随后使用ThenBy()方法。
如果第一个字段是以降序排序,需要使用OrderByDescending()方法,其他字段降序排序需要使用ThenByDescending()方法。
2.2.5Take和Skip
Take()方法对应SQL语句中的Top运算符。
与Take()方法相反的是Skip()方法,它可以跳过前n个结果,返回剩余的结果。
Take()和Skip()在Linq中成为分区运算符。
varresult=list.OrderBy(stu=>stu.Age); Console.WriteLine("年龄最小的两名学员是:"); foreach(varstuinresult.Take(2)) { Console.WriteLine(stu); } Console.WriteLine("其他学员依次为:"); foreach(varstuinresult.Skip(2)) { Console.WriteLine(stu); } |
运行结果:
2.2.6First和FirstOrDefault
First()方法用来查找集合中第一个匹配的元素,如果没有找到匹配的结果则会引发一个异常。可以使用FirstOrDefault()方法避免异常的发生。
示例代码:
Console.WriteLine("姓名为lisi的同学信息:"); Console.WriteLine(list.First(stu=>stu.Name=="lisi")); Console.WriteLine("姓名为hanjiu的同学信息:"); Console.WriteLine(list.FirstOrDefault(stu=>stu.Name=="hanjiu")); |
FirstOrDefault()方法若没有找到则返回有一个空。
2.2.7集运算符
Linq提供了标准的集运算符,如Union()和Intersect(),对查询结果执行操作,上一章的Distinct()也是一个集运算符。
下面定义一个分数类
classScore
{
publicintID{get;set;}
publicintscore{get;set;}
}
示例代码:
staticvoidMain(string[]args) { List<Student>list=newList<Student>{ newStudent{ID=1,Name="zhangsan",Sex="男",Age=18,Class=50}, newStudent{ID=2,Name="lisi",Sex="男",Age=18,Class=50}, newStudent{ID=3,Name="wuangwu",Sex="男",Age=20,Class=51}, newStudent{ID=4,Name="zhaoliu",Sex="男",Age=20,Class=52}, newStudent{ID=5,Name="zhouqi",Sex="女",Age=21,Class=52}, newStudent{ID=6,Name="wangba",Sex="女",Age=20,Class=52} }; List<Score>Scores=newList<Score>{ newScore{ID=1,score=80}, newScore{ID=2,score=90}, newScore{ID=3,score=70}, newScore{ID=4,score=60}, newScore{ID=5,score=50}, newScore{ID=7,score=40}}; varstudent=fromsinlistselects.ID; varscore=fromscrinScoresselectscr.ID; varstuWithScore=student.Intersect(score); Console.WriteLine("有成绩的学员编号为:"); foreach(variteminstuWithScore) { Console.WriteLine(item); } Console.WriteLine("未知学员的成绩编号为:"); varscoreNoStu=score.Except(student); foreach(variteminscoreNoStu) { Console.WriteLine(item); } Console.WriteLine("所有的编号为:"); varallID=score.Union(student); foreach(variteminallID) { Console.WriteLine(item); } } |
Intersect()查找在Student结果中有成绩的学员编号,
Except()用于查找没有匹配学员的成绩编号
Union()预算法用于查找两个结果的并集,要删除重复项
集运算符要求集成员有相同的类型才能确保得到希望的结果。
2.2.8Join查询
Join可以用一个查询搜索两个列表中相关的数据,用关键字段把结果连接起来。类似于SQL中join(内连接)操作。如:
varresult=fromstuinlistjoinscrinScoresonstu.IDequalsscr.IDselectnew{stu.ID,stu.Name,scr.score}; foreach(varssinresult) { Console.WriteLine(ss); } |