LINQ的全称是Language Integrated Query,中文译成“语言集成查询”。LINQ作为一种查询技术,首先要解决数据源的封装,大致使用了三大组件来实现这个封装,分别是LINQ to Object、LINQ to ADO.NET、LINQ to XML。它们和.NET语言的关系如下:
要使用LINQ来编程,首先要学习使用LINQ的子句以及由查询语法构成的查询表达式。C#3.0和VB9开始将这种查询语法引入到了编程语言,并新增了一系列的关键字。但对于CLR本身来说,它并不了解查询语法,它能理解的是由编程语言的编译器将这种查询语法转换成的方法。这些方法叫“标准查询运算符”,它们具有类似这样的名称——Where、Select、GroupBy、Join。下面就以C#为例,从编程语言的层面来具体介绍这些查询语法(注意VB9也支持这种查询语法)。
LINQ的查询由3基本部分组成:获取数据源,创建查询,执行查询。
// 1,获取数据源 List<int> numbers = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; // 2,创建查询 var numQuery = from num in numbers where num % 2 == 0 select num; // 3,执行查询 foreach (var num in numQuery) { Console.WriteLine("{0,1}", num); }
下图显示了完整的查询操作。在 LINQ 中,查询的执行与查询本身截然不同;换句话说,如果只是创建查询变量,则不会检索任何数据。
如上例所示,Linq的数据源要求必须实现IEnumerable或IEnumerable<T>接口,数组隐式支持这个接口。numQuery叫做查询变量,它存储了一个查询表达式。注意,声明查询变量并不会执行查询,真正的执行查询延迟到了foreach语句中。
2. from子句创建一个LINQ表达式必须要以from子句开头。
2.1 单个from子句string[] values = { "中国", "日本", "美国", "菲律宾", "越南" }; //查询包含“国”的字符串 var valueQuery = from v in values where v.IndexOf("国") > 0 select v; foreach (var v in valueQuery) { Console.WriteLine("{0,1}", v); }
在这个LINQ表达式的from子句中,v叫做范围变量,values是数据源。v的作用域存在于当前的LINQ表达式,表达式以外不能访问这个变量。where用来筛选元素,select用于输出元素。这里的范围变量v,和foreach语句中得隐式变量v都可以由编译器推断出其类型。
运行的结果如下:
中国 美国
使用LINQ查询List<T>集合
public class CustomerInfo { public string Name { get; set; } public int Age { get; set; } public string Tel { get; set; } } private void formExpDemo2() { //这里用了,对象和集合初始化器 List<CustomerInfo> customers = new List<CustomerInfo> { new CustomerInfo{, Age=35, Tel ="1330708****"}, new CustomerInfo{, Age=17, Tel ="1592842****"}, new CustomerInfo{, Age=23, Tel ="1380524****"} }; //查询年龄大于20的客户,注意这里的范围变量用了显示类型CustomerInfo var query = from CustomerInfo ci in customers where ci.Age > 20 select ci; foreach (CustomerInfo ci in query) { Console.WriteLine("姓名:{0} 年龄:{1} 电话:{2}", ci.Name, ci.Age, ci.Tel); } }
结果:
姓名:欧阳晓晓 年龄:35 电话:1330708**** 姓名:诸葛菲菲 年龄:23 电话:1380524****
2.2 复合from子句在查询数据源中,元素的属性是一个集合时,可以使用复合from子句对这个属性集合查询。比如,一个客户,可能有多个电话。
public class CustomerInfo { public string Name { get; set; } public int Age { get; set; } public List<string> TelTable { get; set; } } private void formExpDemo() { List<CustomerInfo> customers = new List<CustomerInfo> { new CustomerInfo{, Age=35, TelTable=new List<string>{"1330708****","1330709****"}}, new CustomerInfo{, Age=17, TelTable=new List<string>{"1592842****","1592843****"}}, new CustomerInfo{, Age=23, TelTable=new List<string>{"1380524****","1380525****"}} }; //查询包含电话号码1592842****的客户 var query = from CustomerInfo ci in customers from tel in ci.TelTable where tel.IndexOf("1592842****") > -1 select ci; foreach (var ci in query) { Console.WriteLine("姓名:{0} 年龄:{1}", ci.Name, ci.Age); foreach (var tel in ci.TelTable) { Console.WriteLine(" 电话:{0}", tel); } } }
结果:
姓名:上官飘飘 年龄:17 电话:1592842**** 电话:1592843****
2.3 多个from子句