Skip to content

Latest commit

 

History

History
173 lines (95 loc) · 7.26 KB

linq.md

File metadata and controls

173 lines (95 loc) · 7.26 KB

LINQ 语言集成查询

LINQ是微软提供的一项技术,具体内容可以查看LINQ概述,本文仅仅保证可以使用LINQ与Mirai.Net简单配合,并不是一门正式的LINQ教程!

LINQ是原生提供的内容,不需要安装额外的包,只需要在文件开头添加using System.Linq;就可以使用LINQ提供的一系列方法,它们全部为扩展方法。

> 如果你在想自己的代码为何没有Where、OfType等方法,尝试添加using System.Linq;与using System.Reactive.Linq;,只有后者才可以将LINQ应用在接收消息和接收事件的IObservable可观测对象

快速理解LINQ

虽然LINQ的查询方式,查询对象有很多种,但是为了快速理解LINQ,我们在这里可以给LINQ下一个定义为:

> LINQ就是以一种类似于SQL语句 *(这里指所使用内容的命名相似)*的形式,对集合进行快速操作的工具

如果你不能理解上述内容,可以把SQL语句相关内容删去,只知道LINQ是一个操作集合的工具就可以了。

LINQ的形式

LINQ有两种形式,分别是查询表达式和链式表达式。

查询表达式如下:

var list = new List<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var result =
    from n in list
    where n % 2 == 0
    select n;

此时如果你去遍历result并输出值,你会获得1到10内所有的偶数。这种方法与SQL语句特别相似。

用链式表达式实现上述内容如下:

var list = new List<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var result = list
    .Where(x => x % 2 == 0);

result内容与上述相同。

我们由此可得:

> 查询表达式是用类似于SQL语句的方式对集合进行操作,而链式表达式则是用方法的调用对集合进行操作。

由于查询表达式比较难(其实不难,但是我不会),且可读性不适合初学者,所以我们后文全部使用链式表达式。

LINQ的具体使用

支持LINQ的类型需要实现IEnumerable<T>接口,T表示元素类型。

LINQ的链式表达式使用一系列方法处理集合,每个方法的返回值为处理后的集合 (即IEnumerable<T>引用,听不懂的话就认为返回的对象一定实现了IEnumerable<T>接口就行了),所以可以一个方法接着一个方法。

LINQ的方法实际上全部是泛型的,但是在绝大多数情况下这些类型都可以自动推断,只需要当普通方法用就行了。

LINQ的方法其中一部分会需要传入参数,而这个参数为委托,换句话来说就是把方法当做参数传进去了,但是大部分情况下我们都没有时间专门定义一个来传入,名字就容易想半天,所以可以采用一种快速编写匿名函数的方法——Lambda表达式 它的语法如下:

> (参数列表) => {语句块}

因为编译器会自动推算参数类型(在使用LINQ的大部分场景下),所以参数列表可以只写名字不写类型,在这其中,如果只有一个参数(不带类型),可以省去参数列表外层的小括号,没有参数,或者参数与参数类型出现的数量超过了一个就要加括号(说人话就是省括号只能有一个词)。

如果语句块只有一条语句的话,那么语句块外层的大括号可以省略,同时如果这个函数有返回值的话,语句块末尾出现的return关键字也可以在只有一条语句省略大括号情况的时候省略不写,这条语句的返回值会自动作为该函数的返回值被返回。而如果省略了大括号,这条语句末尾的分号;也可以省略不写(我指对于Lambda表达式来说是不写的,Lambda表达式一定是包含在其它语句里的那这整条语句的分号肯定要写啊)。

下面对常用方法进行举例:

Where方法

Where方法用于筛选集合,参数为以下的Lambda表达式:

  • 元素 => {语句块,返回布尔值}

  • (元素, 索引) {语句块,返回布尔值}

当该元素被传入Lambda表达式返回的值为true时,被Where方法返回的集合中会加入该元素。

示例如下:

var list = new List<int>{ 10, 12, 14, 17 };

var result = list.Where(x => x > 15); // 返回所有大于15的数字所组成的集合
var list = new List<int>{ 10, 12, 14, 17 };

var result = list.Where((item, index) => index % 2 == 0) // 返回所有索引为偶数的数字所组成的集合

Select方法

Select方法用于投影集合,相当于把每个元素做处理之后返回一个新的集合,每一个元素被处理后都会进入新集合,这个集合的元素类型可以不与原集合相同,参数为以下的Lambda表达式:

  • 元素 => {语句块,有返回值}

  • (元素, 索引) => {语句块,有返回值}

示例如下:

var list = new List<int>{ 10, 12, 14, 17 };

var result = list.Select(x => x++); // 返回所有元素加一组成的集合
var list = new List<int>{ 10, 12, 14, 17 };

var result = list.Select((item, index) => index); // 返回所有元素的索引组成的集合

OrderBy方法 & OrderByDescending方法

OrderBy方法用于排序集合,排序顺序为升序(从小到大),参数为以下内容:

  • 元素 => {语句块,返回可比较对象}

  • 元素 => {语句块,有返回值}, 比较器

可比较对象为以下三个内容:

  • 至少实现了比较运算符中的<>的对象

  • 实现了IComparable接口的对象

  • 实现了IComparable的方法CompareTo的对象

比较器为以下两个内容:

  • 实现了IComparer接口的对象

  • 实现了IComparer的方法Compare的对象

OrderByDescending方法与OrderBy相同,排序方式为降序(从大到小)。

First、Last、Single方法 & FirstOrDefault、LastOrDefault、SingleOrDefault方法

First、Last、Single方法用于获得集合中的第一个,最后一个或唯一一个元素,参数为空或以下的Lambda表达式(即所求元素必须满足该Lambda表达式):

  • 元素 => {语句块,返回布尔值}

如果所求元素不存在(或Single方法所处理的集合中并非有且只有一个元素),则抛出异常。

FirstOrDefault、LastOrDefault、SingleOrDefault方法与上述相同,但是在未找到元素时会返回类型默认值(或所给默认值),参数为空或以下内容:

  • 默认值

  • 元素 => {语句块,返回布尔值}

  • 元素 => {语句块,返回布尔值}, 默认值

OfType<TResult>方法

OfType<TResult>方法用于筛选集合元素类型,必须填写泛型内容,没有参数。

Any方法

Any方法用于确定集合中是否存在元素,参数为空或以下的Lambda表达式(即存在的元素必须满足该Lambda表达式):

  • 元素 => {语句块,返回布尔值}

如果不存在任何元素(或满足条件的元素)将返回false,如果存在将返回true。

All方法

All方法用于确定集合中的所有元素是否都满足条件,参数以下的Lambda表达式(即所有元素都必须满足该Lambda表达式):

  • 元素 => {语句块,返回布尔值}

如果所有元素都满足条件将返回true,否则返回false。