?
Linq基础
1.1?LINQ简介
LINQ(Language?Integrated?Query)是C#3.0语言新增的一个扩展,可以处理非常大的对象集合,这一般需要选择集合的一个子集来完成执行程序的任务。Linq提供了很多扩展方法便于集合的排序、组合和计算查询结果的统计数据。
VS2008带有3个内置的LINQ变体:?Linq?to?Objects??Linq?to?SQL??Linq?to?XML,它们为不同的数据提供了查询方案:
Linq?to?Objects:为任意类型的C#内存对象提供查询,如数组、列表和其它集合类型。
Linq?to?SQL:为使用标准SQL数据库查询语言的关系数据库提供查询,如SQL?Server、Oracle等数据库。
Linq?to?XML:提供XML文档的创建和处理功能。
1.2?第一LINQ查询
下面我们使用Linq实现一个对数组的查找功能,代码如下:
示例1
|
class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????string[]?names?=?{?"alonso",?"zheng",?"smith",?"jones",?"smythe",?"small",?"Ruiz",?"Hsieh",?"Jorgenson",?"Ilyich",?"singh"?};
????????????var?result?=?from?n?in?names?where?n.StartsWith("s")?select?n;
????????????Console.WriteLine("以s开头的名字为:");
????????????foreach?(var?item?in?result)
????????????{
????????????????Console.WriteLine(item);
????????????}
????????}
????}

示例说明:
(1)?命名空间:System.Linq;
(2)?用var关键字声明结果变量;var声明的变量不用指定类型,编译器会自动根据结果推断出该类型。这种声明方式只适用于局部变量。
(3)?from子句:指定数据源,?类似于foreach循环语法
(4)?where子句:指定条件,可以在该子句中指定能应用于数据源中各元素的任意布尔表达式。Where是可选的,称为限制运算符。StartsWith()指定以字母“s”开头,类似的还有Length()(长度)、Contains()(包含)。
(5)?select子句:指定元素。必须的,指定结果集中有哪些元素。
(6)?foreach语句:负责执行Linq查询的代码。result仅保存了执行查询的一个计划,在访问查询结果之前,并没有提取Linq数据,这称为查询的延迟执行。
1.3?排序查询结果
用where子句找到感兴趣的数据后,Linq还可以方便的对得到的数据执行进一步处理,例如,给结果重新排序。下面的示例将以字母顺序给上一个查询的结果排序
示例2
static?void?Main(string[]?args)
????????{
????????????string[]?names?=?{?"alonso",?"singh"?};
????????????var?result?=?from?n?in?names?where?n.StartsWith("s")?orderby?n?select?n;
????????????Console.WriteLine("以s开头的名字为:");
????????????foreach?(var?item?in?result)
????????????{
????????????????Console.WriteLine(item);
????????????}
????????}

示例说明:这个程序与示例1几乎相同,只是在查询子句中增加了一行代码:
orderby?n
即实现了对结果的排序功能。与where子句一样,orderby子句是可选的。
Orderby子句默认为升序,但可以添加descending关键字,指定降序排列。如:
Orderby?n?descending;
另外,可以按照任意表达式进行排序,而无需重新编写查询。例如,要按照姓名中的最后一个字母顺序排序,只需添加如下子句:
?Orderby?n.Substring(n.Length-1);
1.4?合计运算符
运算符
说明
Count()
结果的个数
Min()
结果中的最小值
Max()
结果中的最大值
Average()
数字结果的平均值
Sum()
所有数字结果的和
使用合计运算符会强制立即执行,而不是延迟执行
示例3
class?Program
{
????static?void?Main(string[]?args)
????{
????????????int[]?numbers?=?CreateNumbers(123456);
????????????var?result?=?from?n?in?numbers?where?n?>?1000?select?n;
????????????Console.WriteLine("大于1000的个数为:"?+?result.Count());
????????????Console.WriteLine("大于1000的最大数为:"?+?result.Max());
????????????Console.WriteLine("大于1000的最小数为:"?+?result.Min());
????????????Console.WriteLine("大于1000的平均数为:"?+?result.Average());
????????????Console.WriteLine("大于1000的数的和为:"?+?result.Sum(n=>(long)n));
????}
????private?static?int[]?CreateNumbers(int?count)
????{
????????Random?rand?=?new?Random(0);
????????int[]?result?=?new?int[count];
????????for?(int?i?=?0;?i?<?count;?i++)
????????{
????????????result[i]?=?rand.Next();
????????}
????????return?result;
????}
}

示例说明:
Sum()注意,在此给Sum()方法传入了一个λ表达式n=>(long)n,以获得所有数字的和。只是Sum()的一个重载。由于和的结果太大,若个只是用Sum()会产生溢出。?
1.5?查询复杂对象
下面我们利用Linq来查询对象。
示例4
//?Student类
class?Student
{
????public?int?ID?{?get;?set;?}
????public?string?Name?{?get;?set;?}
????public?string?Sex?{?get;?set;?}
????public?int?Age{?get;?set;?}
????public?int?Class?{?get;?set;?}
????public?override?string?ToString()
????{
????????return?"ID:"?+?ID?+?"tName:"?+?Name?+?"tSex:"?+?Sex?+?"tAge:"?+?Age?+?"tClass:"?+?Class;
????}
}
//main?方法
static?void?Main(string[]?args)
{
????List<Student>?list?=?new?List<Student>{
????????new?Student{ID=1,Name="zhangsan",Sex="男",?Age=18,Class=50},
????????new?Student{ID=2,Name="lisi",
????????new?Student{ID=3,Name="wuangwu",?Age=20,Class=51},
????????new?Student{ID=4,Name="zhaoliu",Class=52},
????????new?Student{ID=5,Name="zhouqi",Sex="女",?Age=21,
????????new?Student{ID=6,Name="wangba",Class=52}
????};
????var?result?=?from?stu?in?list?where?stu.Age?==?18?select?stu;
????Console.WriteLine("年龄为18的学员为:");
????foreach?(var?stu?in?result)
????{
????????Console.WriteLine(stu);
????}
}

示例说明:
给示例和其它示例相似,只是查询的集合为对象集合,结果也为对象。
1.6?投射:在查询中创建新对象
投射是在Linq查询中从其它数据类型中创建新数据类型的技术术语。Select关键字是投射运算符。
如Sql数据查询语言,select用来从数据表中选择适当的字段,在Linq中select与其类似。例如将示例4中的代码改为如下:
var?result=from?stu?in?list?where?stu.Age=18?select?stu.Name;
其运行结果为:
Zhangsan
Lisi
甚至可以通过给select添加表达式,来转换查询中的数据。如:
select?n+1;
select?stu.Name.ToUpper();
但是与sql不同,Linq不允许在select子句中有多个字段,即select?stu.Name,stu.Age这样的形式将产生一个错误。
如果要实现上述情况,需要在select子句中创建一个新对象,来保存查询的结果。
示例5
//修改示例4Main方法
var?result?=?from?stu?in?list?where?stu.Age?==?18?select?new?(stu.Name,stu.Age);
????Console.WriteLine("年龄为18的学员为:");
????foreach?(var?stu?in?result)
????{
????????Console.WriteLine(stu);
????}
1.7?单值选择查询------Distinct
Sql中我们用到过select?distinct查询,改查询可检索数据中的唯一值,也就是说值不是重复的。在Linq中作用与之类似。例如:
var?result?=?list.Select(stu=>stu.Class).Distinct();
其结果为:
50
51
52
此示例为方法语法,将在后期降到。需要说明的是Distinct()只能用在方法语法中。
1.8?多级排序
处理了带多个属性的对象后,要考虑按多种方式进行排序的问题了,例如我们先按照班级排序,在按照年龄排序。代码如下:
var?result=from?stu?in?list?orderby?stu.Class,stu.Age?select?stu;
结果如下:

还可以给字段添加Descending关键字。如
orderby?stu.Class,stu.Age.deseending;
1.9?组合查询
在Linq中还可以实现像Sql中的Group?by语句一样的分组统计功能。
var?result=from?stu?in?list?group?stu?by?stu.Class?into?student?select?new?{Class=student.Key,Count=student.Count()};
var?orderresult=from?student?in?result?orderby?student.Count?descending?select?student;
其运行结果为

在组合查询中的数据通过一个键(key)字段来分组,每个组中的所有程序都共享这个字段值,在此例中键字段是Class:
group?stu?by?stu.Class
要计算每个组的数量,应该生成一个新的结果集student:
group?stu?by?stu.Class?into?student
var?result=from?stu?in?list?group?stu?by?stu.Class?into?student?select?new?{Class=student.Key,Count=student.Count()};
var?orderresult=from?student?in?result?orderby?student.Count?descending?select?student;
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!