一、什么是Linq To Objects
从根本上说,Linq To Objects表示一种新的处理集合的方法。采用旧方法,必须编写指定如何从集合检索数据的复杂的foreach循环。而采用Linq方法,只需要编写描述要检索的内容的声明性代码。
二、使用Linq To Objects的优势
与传统的foreach循环相比,Linq查询具有三大优势:
- 更简明、更易读、尤其是在筛选多个条件时。
- 使用最少的应用程序代码提供强大的筛选、排序和分组功能。
- 无需修改或只需很小的修改即可将它们移植到其他数据源。
通常,对数据执行的操作越复杂,使用Linq代替传统迭代技术的好处就越多。
三、Linq To Objects技术的介绍和演示
1、Linq和字符串
Linq可用于查询和转换字符串和字符串集合。它对文本文件中的半结构化数据尤其有用。Linq查询可与传统的字符串函数和正则表达式结合使用。
2 /// 查询指定字符串在文章中出现的次数
3 ///</summary>
4 publicstaticvoid GetStringCount()
5 {
6 //数据源
7 string article =
@"The Endorsed Standards for Java SE constitute all classes and "+
8 @" interfaces that are defined in the packages listed in this section. "+
9 @"Classes and interfaces defined in sub-packages of listed packages"+
10 @" are not Endorsed Standards unless those sub-packages are themselves listed."+
11 @" The Endorsed Standards Override Mechanism may be used to override the Java SE"+
12 @" platform packages in this list, and these packages may be"+
13 @" overridden only by versions of the Endorsed Standard that"+
14 @"are newer than that provided by the Java platform as released by Sun."+
15 @" With the exception of packages listed here and the technologies "+
16 @"listed in the Standalone Technologies section below, no other "+
17 @" packages from the Java SE platform API specification may be overridden.";
18
19 //根据字符数组中匹配的符号,分割字符串得到一个存放单词的字符串数组
20 string[] words = article.Split(newchar[] { '.', '' });
21
22 //把单词数组中packages查询出来
23 var query = from word in words
24 where word =="packages"
25 select word;
26
27 //输出文章中一共有多少个packages
28
29 Console.WriteLine("packages出现过{0}次", query.Count());
30 Console.Read();
31 }
需求:从这段文字节选中查找"packages"出现的次数
分析:先用字符串示例方法split(char[] arr)方法,将字符串转换成单词数组,然后使用Linq查询,遍历单词数组中的每个单词,筛选出所有的"packages",然后调用Count()方法统计出有多少个"packages"。
2 /// 获取字符串中的数字
3 ///</summary>
4 publicstaticvoid GetDigitFromString()
5 {
6 //字符串数据源
7 string strr ="sdfsdf232sd09sdfds";
8
9 //查询字符串中是数字的查询语句
10 var query = from ch in strr
11 where Char.IsDigit(ch)
12 select ch;
13
14 //执行查询并输出结果
15 foreach (var ch in query)
16 {
17 Console.WriteLine(ch+",");
18 }
19
20 Console.Read();
21 }
需求:获取字符串中的数字
分析:使用Linq遍历字符串中每个字母(字符串类型已经实现了IEnumerable接口,所以可以使用Linq查询),然后调用Char类的静态方法IsDigit(char c)进行筛选,筛选出数字返回。
2、Linq和反射
.NET Framework类库反射API可用于检查.NET程序集中的元数据,及创建位于该程序集中的类型、类型成员、参数等等的集合,因为这些集合支持泛型IEnumerable(T)接口,所以可以使用Linq查询它们。
2 /// Linq To Reflection测试方法
3 ///</summary>
4 publicstaticvoid TestReflection()
5 {
6 //程序集的文件路径
7 string file =
8 @"G:OrderingSystemBLLinDebugOrderingSystemBLL.dll";
9
10 //加载该程序集
11 Assembly assembly = Assembly.LoadFrom(file);
12
13 //查询程序集中所有的公共类中的公共方法,根据类来分组的查询语句
14 var query = from type in assembly.GetTypes()
15 where type.IsPublic
16 from method in type.GetMethods()
17 where method.IsPublic
18 group method by type;
19
20 //执行查询并输出结果
21 foreach (var methods in query)
22 {
23 Console.WriteLine(methods.Key+": ==================================== ");
24 foreach (var method in methods)
25 {
26 Console.WriteLine(method.ToString());
27 }
28 }
29
30 Console.Read();
31 }
需求:将OrderingSystemBLL.dll程序集中所有公共类中的公共方法输出到控制台
分析:首先找到OrderingSystemBLL.dll程序集,并加载该程序集,然后通过Linq查询便利程序集中每个元素,筛选出是用Public修饰的类,然后再遍历这些类中的每个方法,筛选出是Public修饰的,并且以类型分组返回。
3、Linq和文件目录
许多文件系统操作实质上是查询,因此非常适合使用Linq方法。
2 /// Linq to FileInfo测试方法
3 ///</summary>
4 publicstaticvoid TestLinqToFileInfo()
5 {
6 //指定路径
7 string path =@"G:MyOffice";
8
9 //获取该路径的所有文件信息,作为数据源
10 IEnumerable<System.IO.FileInfo> files = GetFiles(path);
11
12 //查询该文件信息集合中最近创建的后缀名为.aspx的文件
13 var query = (from file in files
14 where file.Extension ==".aspx"
15 orderby file.CreationTime descending
16 select file).First();
17
18 //输出结果
19 Console.WriteLine(query.Name + ":" + query.CreationTime);
20
21 Console.Read();
22 }
23
24 ///<summary>
25 /// 获取指定路径的所有文件信息
26 ///</summary>
27 ///<param name="path">指定路径</param>
28 ///<returns>指定路径的所有文件信息</returns>
29 publicstatic IEnumerable<System.IO.FileInfo> GetFiles(string path)
30 {
31 //如果不存在该路径,提示用户该路径不存在
32 if (!System.IO.Directory.Exists(path))
33 {
34 Console.WriteLine("该路径不存在!");
35 }
36
37 //定义一个存放文件名信息的数字
38 string[] fileNames =null;
39
40 //定义一个存放文件信息的集合
41 IList<System.IO.FileInfo> fileInfoList =new List<System.IO.FileInfo>();
42
43 //根据路径和查询条件在所有的子目录下获得文件名
44 fileNames = System.IO.Directory.GetFiles(path, "*.*",
45 System.IO.SearchOption.AllDirectories);
46
47 //循环遍历,将文件信息添加到集合中
48 foreach (var fileName in fileNames)
49 {
50 fileInfoList.Add(new System.IO.FileInfo(fileName));
51 }
52
53 return fileInfoList;
54 }
需求:查询出指定文件目录下,最近被修改过的后缀名为".aspx"的文件打印到控制台
分析:使用GetFiles方法将指定目录下的所以的文件目录和文件加载,遍历文件信息集合中每个文件信息,筛选出后缀名为".aspx"的文件信息,并且根据创建时间进行倒序排序,取第一个返回。
4、Linq和ArrayList
在使用Linq查询非泛型IEnumerable集合(如:ArrayList)时,必须显示声明范围变量的类型以反映此集合中对象的特定类型。
2 /// Linq To ArrayList测试方法
3 ///</summary>
4 publicstaticvoid TestLinqToArrayList()
5 {
6 //数据源为ArrayList
7 ArrayList studentList =new ArrayList
8 {
9 new Student
10 {
11 ID =1,
12 Name ="Jackie",
13 Scores =newint[]{92,82,88,72}
14 },
15
16 new Student
17 {
18 ID =2,
19 Name ="Kevin",
20 Scores =newint[]{90,82,68,72}
21 },
22
23 new Student
24 {
25 ID =3,
26 Name ="Helen",
27 Scores =newint[]{82,82,88,72}
28 },
29
30 new Student
31 {
32 ID =4,
33 Name ="Jim",
34 Scores =newint[]{78,82,83,72}
35 }
36 };
37
38 //查询第一门课程成绩90分以上的学生
39 var query = from Student stu in studentList
40 where stu.Scores[0] >90
41 select stu;
42
43 //执行查询并输出结果
44 foreach (var stu in query)
45 {
46 Console.WriteLine(stu.Name);
47 }
48
49 Console.Read();
50 }
需求:查询ArrayList集合中第一门成绩90分以上的学生
分析:遍历ArrayList集合中每个学生(注意ArrayList是个非泛型集合,因此这里的范围类型stu的类型必须显示声明为Student),筛选出第一门成绩大于90的学生对象返回。
四、查询操作中的类型关系
- Linq查询操作在数据源、查询本身及查询执行中是强类型的。
- 查询中变量的类型必须与数据源中元素的类型和foreach语句中迭代变量的类型兼容
- 此强类型保证在编译时捕获类型错误,以便可以在用户遇到这些错误之前更正它们。
1、不转换源数据的查询
- 数据源的类型参数决定范围变量的类型。
- 选择的对象的类型决定查询变量的类型,此处的name为一个字符串。因此,查询变量是一个IEnumerable<string>。
- 在foreach语句中循环访问查询变量。因为查询变量是一个字符串序列,所以迭代变量也是一个字符串。
2、转换源数据的查询
- 数据源的类型参数决定范围变量的类型。
- select语句返回Name属性,而非完整的Customer对象。因为Name是一个字符串,所以custNameQuery的类型参数是string而非Customer.
- 因为custNameQuery是一个字符串序列,所以foreach循环的迭代变量也必须是string。
3、编译器推断类型的查询
- 数据源的类型参数始终为查询中的范围变量的类型。
- 因为select语句生成匿名类型,所以必须使用var隐式类型化查询变量。
- 因为查询变量的类型是隐式的,所以foreach循环中的迭代变量也必须是隐式的。
五、查询语法和方法语法
通过使用C# 3.0 中引入的声明性查询语法,介绍性LINQ 文档中的多数查询都被编写为查询表达式。但是,.NET 公共语言运行库 (CLR)本身并不具有查询语法的概念。因此,在编译时,查询表达转换为CLR 确实了解的内容:方法调用。这些方法称为“标准查询运算符”,它们具有如下名称:Where、Select、GroupBy、Join、Max、Average 等。