为LINQ写序,也为人生的新篇章写序,简单的人生简单的linq。
-------------------------------------------------------------------------------------------
本人选用《LINQ实战》人民邮电 一书学习。根据目前项目要求展开学习。
根据实际情况我要较快的掌握熟练应用,故从第三章《LINQ构建块》开始学习。
本章重点介绍构建LINQ的核心元素。
此图为第二章所讲内容,简单说明一下LINQ组成
3.1.2构成LINQ基础的核心元素
3.2序列
3.2.1IEnumerable<T>接口
上述代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace linqS3
{
class Program
{
static void Main(string[] args)
{
DisplayProcess();
Console.Read();
}
static void DisplayProcess()
{
var processes =
Process.GetProcesses()
.Where(process => process.WorkingSet64 > 20 * 1024 * 1024)
.OrderByDescending(process => process.WorkingSet64)
.Select(process => new { process.Id, Name = process.ProcessName });
ObjectDumper.Write(processes);
}
}
}
其中Process.GetProcesses方法的返回值是一个Process对象数组,这个数组实现了IEnumerable<T>接口。
是否实现了IEnumerable<T>接口的数组就是本书所谓序列呢?
Where,OrderByDescending,Select这些方法均定义在IEnumerable<T>接口之上,都属于扩展方法。
下面是Where方法的实现
public static IEnumerable<Tsource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, Boolean> pedicate)
{
foreach (TSource element in source)
{
if (Predicate(element))
yield return element;
}
}
yield return这个语句及返回值类型IEnumerable<Tsource>构成了一个迭代器。
3.2.2迭代器
迭代器允许我们依次地访问集合中的每一个元素。类似数据库里的游标。
foreach就是典型的迭代器,集合(除数组)的GetEnumerator方法是foreach遍历实现的方法。
简单的迭代器
static void Main(string[] args)
{
foreach(var number in OneTwoThree())
{
Console.WriteLine(number);
}
Console.Read();
}
static IEnumerable<int> OneTwoThree()
{
Console.WriteLine("Returning 1");
yield return 1;
Console.WriteLine("Returning 2");
yield return 2;
Console.WriteLine("Returning 3");
yield return 3;
}
显示结果如下:
Returning 1
1
returning 2
2
returning3
3
foreach在迭代器返回值后,将控制权交给了迭代器。
此例可以看出迭代器是逐个工作的。否则,直接返回
1
2
3
(协同程序含有yield return语句,否则都是C#子程序)
3.2.3延迟查询
1 演示延迟查询执行
static void Main(string[] args)
{
//延迟查询执行
int[] nubers = { 1, 2, 3 };
var query = from n in nubers select Square(n); //---------------1
foreach (var n in query)
Console.WriteLine(n);
Console.Read();
}
static double Square(double n)
{
Console.WriteLine("Computing Square(" + n + ")");
return Math.Pow(n, 2);
}
执行结果
Computing Square (1)
1
Computing Square (2)
4
Computing Square (3)
9
说明“--------------------1”的时候并没有打印所有的值,直到foreach的时候才执行。
2.重用查询以得到不同的结果
当第二次迭代访问查询时,可能得到不同的结果。
(原因是数据源被改变了,至少从示例看是这样的,也许这只是抽象的告诉我们注意在复杂环境中可能会出现这类问题,注意源数据)
int[] numbers = { 1, 2, 3 };
var query = from n in numbers select Square(n);
foreach (var n in query)
Console.WriteLine(n);
Console.WriteLine("------------------");
for (int i = 0; i < numbers.Length; i++)
numbers[i] = numbers[i] + 10;
foreach (var n in query)
Console.WriteLine(n);
Console.Read();
3.查询的强制立即执行
代码我有所简化
int[] numbers = { 1, 2, 3 };
var query = from n in numbers select Square(n);
query.ToList();
Console.Read();
ToList方法将依次访问查询的每个结构,并返回List<double>对象。即使foreach再遍历这个List集合,也不会再调用Square方法。
3.3查询操作符
本节对System.Linq.Enumerable类的扩展方法,是LINQ的核心。
3.3.1查询操作符是什么
查询操作符是LINQ查询上下文中使用的,一系列扩展方法的集合。
类似where,orderByDescending,select等方法的实现都是用foreach方法做的迭代器,进行过滤yield return逐个返回值。
他们都接受IEnumerable<T>参数,并返回IEnumerable<T>。
这种扩展方法提高了代码的可读性,
以下是本书对他们的总结共性:
操作于可被美剧的集合对象之上;
允许管道形式的数据处理;
依赖于延迟执行。
可见,查询操作符是LINQ的核心。
3.3.2标准查询操作符
标准查询操作符就是用预定义好的查询操作符来将操作符组合起来完成较为复杂的操作。
3.4查询表达式
3.4.1查询表达式是什么
查询表达式提供了一种集成于语言中的、用来编写查询语句的语法。类似于SQL,意义在于简化查询所需代码,提高查询语句可读性。
通过以下代码对比:
查询操作符
var processes =
Process.GetProcesses()
.Where(process => process.WorkingSet64 > 20 * 1024 * 1024)
.OrderByDescending(process => process.WorkingSet64)
.Select(process => new { process.Id, Name = process.ProcessName });
查询表达式
var processes =
from process in Process.GetProcesses()
where process.WorkingSet64 > 20 * 1024 * 1024
orderby process.WorkingSet64 descending
select new { process.Id,Name=process.ProcessName};
3.4.2编写查询表达式
from [ type ] id source
[ join [type] idin sourceon expr equals expr [into id] ]
{ from [type] idin source |let id = expr | where condition }
[orderby ordering , ordering, ...]
select expr |group expr by key
[into id query]
解释如图
总结:开始于from 结束于select 或group子句,from引入变量,let引入变化范围,where过滤,join两个序列指定字段做比较返回匹配对,into语句切分查询语句让一个语句的结果作为另一个语句的数据源。
3.4.3标准查询操作符与查询表达式的关系
表达式最终会转化成操作符,不是每个操作符都有对应的表达式,表达式只是在某些情况下方便可读。
3.4.4限制
查询操作符有时候优于表达式,所以可以不用表达式。也可以使用表达式的中穿插操作符。
3.5表达式树
3.5.1lambda表达式回顾
lambda表达式主要作用实现匿名委托,lambda表达式也能以数据的形式使用
3.5.2表达式树是什么
表达式树是一棵抽象语法树,编译器和解释器将在进行代码优化及生成时使用到抽象语法树。在高级场合才会使用。
3.5.3IQueryable,另一种实现延迟查询执行的方法
关于表达式内容比较深,这里就不粗浅介绍了。
3.6LINQ的程序集以及命名空间
3.7小结