目录
写在前面
前面的几篇文章算是对linq的铺垫,从本篇开始将进行linq的语法及实践。
系列文章
常见关键字
什么情况下使用linq呢?
可以这样说,只要是实现了IEnumerable<T>接口的对象都可以使用Linq的语法来查询。
而对于只实现了IEnumerable接口而没有实现IEnumerable<T>的对象可以通过如下的方法
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);
来将IEnumerable接口转为IEnumerable<T>(例如ArrayList)。
那么在linq中常见的关键字有那些呢?
在c#3.0中,为linq引入了一下几个关键字:from join where group into let orderby select等。
如果你用过sql,那么你对它们并不陌生。语法很简单,这里就对每个简单的列举一个例子,以便你快速的回忆起他们的用法。
from
from子句是一个Linq查询的开始,任何一个Linq语句都是以from开始,from子句指定查询的容器,和在此语句有效的局部变量。from子句的语法为:
from localParameter in Source
从上面的语法你会发现和foreach何其相似。
foreach(var item in source) { //循环体 }
通过上面的对比,你应该对localParameter和Source有个清楚的认识了。不过在linq中Source必须是实现IEnumerable<T>的对象。下面看一个例子:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 List<int> lstInts = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 6 IEnumerable<int> query = from i in lstInts 7 select i; 8 foreach (var item in query) 9 { 10 Console.WriteLine(item); 11 } 12 Console.Read(); 13 } 14 }
结果
举得例子其实并没有实际意义,通过这样的例子,希望对linq有个大概的认识。由于source实现自IEnumerable<T>泛型接口,T可以由source推导出来,在这个例子中T为int。
那么对没有实现IEnumerable<T>而只实现IEnumerable接口的ArrayList,该如何使用linq呢?
此时,就需要我们显式指定局部变量的类型,或者是使用Cast转为IEnumerable<T>
例如:
1 IEnumerable<int> q2 = from i in arry.Cast<int>() 2 select i; 3 //或者 4 var q3 = from int i in arry 5 select i;
select
对查询结果进行投影,有时我们并不需要所有的列,而只需要其中的某几个列的值,此时,select是非常有用的。
下面看一个例子
假如我们有这样一个类
1 class Person 2 { 3 public int ID { set; get; } 4 public string Name { set; get; } 5 public int Age { set; get; } 6 }
我们有这样一个集合
1 List<Person> persons = new List<Person>() 2 { 3 new Person(){ ID=1, Age=20, Name="wolfy"}, 4 new Person(){ID=2,Age=22,Name="angle"} 5 };
现在我们要取出集合中所有人的姓名,即只投影某一列。
1 var pNames = from p in persons 2 select p.Name;
当然我们也可以投影一个集合,此时就需要使用匿名类。
1 var persons2 = from p in persons 2 select new { p.Name, p.Age }; 3 //或者 4 var persons3 = from p in persons 5 select new { name = p.Name, age = p.Age }; 6 foreach (var item in persons3) 7 { 8 Console.WriteLine(item.name + " " + item.age); 9 }
persons3中,在匿名类中,你可以显示的指定投影的列名。
where
对source中的数据进行筛选,看一个例子,选出所有的成年人的姓名。
var persons4 = from p in persons where p.Age > 18 select p.Name;
join
用法类似sql中join,将两个source以某种关系进行关联。
一个例子,查出公司为“北京能力有限公司”的人的名字和所在的公司名字。
1 class Person 2 { 3 public int ID { set; get; } 4 public string Name { set; get; } 5 public int Age { set; get; } 6 public int CompanyID { set; get; } 7 } 8 class Company 9 { 10 public int ID { set; get; } 11 public string Name { set; get; } 12 }
1 List<Person> persons = new List<Person>() 2 { 3 new Person(){ ID=1, Age=20, Name="wolfy",CompanyID=1}, 4 new Person(){ID=2,Age=22,Name="angle",CompanyID=2} 5 }; 6 List<Company> companys = new List<Company>() 7 { 8 new Company(){ ID=1, Name="北京能力有限公司"}, 9 new Company(){ID=2,Name="北京无能有限公司"} 10 }; 11 var result = from p in persons 12 join c in companys on p.CompanyID equals c.ID 13 where c.Name=="北京能力有限公司" 14 select new { Name = p.Name, CompanyName = c.Name }; 15 foreach (var item in result) 16 { 17 Console.WriteLine(item.Name + " " + item.CompanyName); 18 }
结果
注意
join子句只能使用equals或者是not equal而不能用其他运算符(==都不行)。而equals运算符左边必须联接的左部,右边为右部,不能调换的,否则编译不能通过。
into和group
into子句用于将join或者是group子句的结果进一步持续化,包装成为一个System.Linq.IGrouping<TKey, TElement>对象,而且IGrouping继承自IEnumerable<TElement>,IGrouping接口提供分组的键和,该键下所包含的集合。
下面看一个例子
1 List<string> lstNames = new List<string>() { "zhangsan", "lisi", "wanger", "mazi", "zhangwuji" }; 2 var result2 = from n in lstNames 3 group n by n.Length into g 4 select new { g.Key, values = g }; 5 foreach (var group in result2) 6 { 7 Console.WriteLine("{0}:", group.Key); 8 foreach (var item in group.values) 9 { 10 Console.WriteLine(item); 11 } 12 }
结果
let
let子句用于在查询中添加一个新的局部变量,使其在后面的查询中可见,类似sql中为as关键字为字段起别名。
1 var persons4 = from p in persons 2 let age = p.Age 3 where age > 18 4 select p.Name;
Take Skip
用于选取前几个或者和跳过前几个,如选择第11到20个则可以
1 query.Skip(10).Take(10);
跳过前十个,然后再取10条数据。
OrderBy OrderByDescending
query.OrderBy(c => c.Length);
总结
本篇文章介绍了在linq中常见的关键字,他们的作用可以类比sql中的用法。当然还有一些关键字,比如:Distinct Union Intersect Except,这些就不再举例了。感兴趣的可以自己动手试一试。
其它的样例代码可参考:https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
参考文章
http://kb.cnblogs.com/page/100043/