C# 基础知识系列-7 Linq详解
前言
在上一篇中简单介绍了Linq的入门级用法,这一篇尝试讲解一些更加深入的使用方法,与前一篇的结构不一样的地方是,这一篇我会先介绍Linq里的支持方法,然后以实际需求为引导,分别以方法链的形式和类SQL的形式写出来。
前置概念介绍
Predicate<T>
谓词、断言,等价于Func<T,bool>
即返回bool的表达式Expression<TDelegate>
表达式树,这个类很关键,但是在这里会细说,我们会讲它的一个特殊的泛型类型:Expression<Func<T,bool>>
这个在某些数据源的查询中十分重要,它代表lambda表达式中一种特殊的表达式,即没有大括号和return
关键字的那种。
我们先准备两个类:
- Student/学生类:
/// <summary>
/// 学生
/// </summary>
public class Student
{
/// <summary>
/// 学号
/// </summary>
public int StudentId { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 班级
/// </summary>
public string Class { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
}
Subject/科目类:
/// <summary>
/// 科目
/// </summary>
public class Subject
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年级
/// </summary>
public string Grade { get; set; }
/// <summary>
/// 学号
/// </summary>
public int StudentId { get; set; }
/// <summary>
/// 成绩
/// </summary>
public int Score { get; set; }
}
Subject 和Student通过学号字段一一关联,实际工作中数据表有可能会设计成这。
那么先虚拟两个数据源:IEnumerable<Student> students
和 IEnumerable<Subject> subjects
。先忽略这两个数据源的实际来源,因为在开发过程中数据来源有很多种情况,有数据库查询出来的结果、远程接口返回的结果、文件读取的结果等等。不过最后都会整理成IEnumerable<T>
的子接口或实现类的对象。
常见方法介绍
Where 过滤数据,查询出符合条件的结果
where的方法声明:
public IEnumerable<TSource> Where<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate)
可以看出不会转换数据类型,通过给定的lambda表达式或者一个方法进行过滤,获取返回true的元素。
示例:
// 获取年纪大于10但不大于12的同学们
List<Student> results = students.Where(t=>t.Age >10 && t.Age<= 12).ToList();
注意在调用ToList之后数据才会实质上查询出来。
Group 分组,依照指定内容进行分组
Group的方法声明有很多种:
最常用的一种是:
public static IEnumerable<System.Linq.IGrouping<TKey,TSource>> GroupBy<TSource,TKey> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector);
示例:
//将学生按照班级进行分组
List<IGrouping<string,Student>> list = students.GroupBy(p => p.Class).ToList();
OrderBy/OrderByDescending 进行排序,按条件升序/降序
它们是一对方法,一个是升序一个降序,其声明是一样的:
常用的是:
public static System.Linq.IOrderedEnumerable<TSource> OrderBy<TSource,TKey> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector);
示例:
//按年龄的升序排列:
List<Student> results = students.OrderBy(p => p.Age).ToList();
//按年龄的降序排列:
List<Student> results = students.OrderByDescending(p => p.Age).ToList();
First/Last 获取数据源的第一个/最后一个
这组方法有两个常用的重载声明:
First:
// 直接获取第一个
public static TSource First<TSource> (this IEnumerable<TSource> source);
// 获取满足条件的第一个
public static TSource First<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
Last:
// 直接获取最后一个
public static TSource Last<TSource> (this IEnumerable<TSource> source);
// 获取最后一个满足条件的元素
public static TSource Last<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
示例:
Student student = students.First();// 等价于 students[0];
Student student = students.First(p=>p.Class == "一班");//获取数据源中第一个一班的同学
Student student = students.Last();//最后一个学生
Student student = students.Last(p=>p.Class == "三班");//获取数据源中最后一个三班的同学
注意:
- 在某些数据源中使用Last会报错,因为对于一些管道类型的数据源或者说异步数据源,程序无法确认最后一个元素的位置,所以会报错。解决方案:先使用OrderBy对数据源进行一次排序,使结果与原有顺序相反,然后使用First获取
- 当数据源为空,或者不存在满足条件的元素时,调用这组方法会报错。解决方案:调用FirstOrDefault/LastOrDefault,这两组方法在无法查询到结果时会返回一个默认值。
Any/All 是否存在/是否都满足
Any:是否存在元素满足条件
有两个版本,不过意思可能不太一样:
public static bool Any<TSource> (this IEnumerable<TSource> source);//数据源中是否有数据
//================
//是否存在满足条件的数据
public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
All :是否都满足条件:
public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
示例:
// 是否有学生
bool isAny = students.Any();
// 是否有五班的同学
bool isFive = students.Any(p=>p.Class == "五班");
// 是否所有学生的年纪都不小于9岁
bool isAll = students.All(p=>p.Age >= 9);
Skip 略过几个元素
Skip一共有三个衍生方法:
第一个:Skip 自己: 略过几个元素,返回剩下的元素内容
public static IEnumerable<TSource> Skip<TSource> (this IEnumerable<TSource> source, int count);
第二个:SkipLast,从尾巴开始略过几个元素,返回剩下的元素内容
public static IEnumerable<TSource> SkipLast<TSource> (this IEnumerable<TSource> source, int count);
第三个:SkipWhile,跳过满足条件的元素,返回剩下的元素
public static IEnumerable<TSource> SkipWhile<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
示例:
// 不保留前10个学生
List<Student> results = students.Skip(10).ToList();
// 不保留后10个学生
List<Student> results = students.SkipLast(10).ToList();
// 只要非一班的学生
List<Student> results = students.SkipWhere(p=>p.Class=="一班").ToList();
//上一行代码 等价于 = students.Where(p=>p.Class != "一班").ToList();
Take 选取几个元素
Take与Skip一样也有三个衍生方法,声明的参数类型也一样,这里就不对声明做介绍了,直接上示例。
//选取前10名同学
List<Student> results = students.Take(10).ToList();
// 选取最后10名同学
List<Student> results = students.TakeLast(10).ToList();
//选取 一班的学生
List<Student> results = students.TakeWhile(p=>p.Class=="一班").ToList();
// 上一行 等价于 = students.Where(p=>p.Class=="一班").ToList();
在使用Linq写分页的时候,就是联合使用Take和Skip这两个方法:
int pageSize = 10;//每页10条数据
int pageIndex = 1;//当前第一页
List<Student> results = students.Skip((pageIndex-1)*pageSize).Take(pageSize).ToList();
其中 pageIndex可以是任意大于0 的数字。Take和Skip比较有意思的地方就是,如果传入的数字比数据源的数据量大,根本不会爆粗,只会返回一个空数据源列表。
Select 选取
官方对于Select的解释是,将序列中的每个元素投影到新的表单里。我的理解就是,自己 定义一个数据源单个对象的转换器,然后按照自己的方式对数据进行处理,选择出一部分字段,转换一部分字段。
所以按我的理解,我没找到java8的同效果方法。(实际上java用的是map,所以没找到,
C# 基础知识系列-7 Linq详解的更多相关文章
- vue.js基础知识篇(6):组件详解
第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...
- 《Java基础知识》Java注解"@"详解
Java注解含义: Java注解,顾名思义,注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的.Java注解又叫java标注,java提供了一套机制,使得 ...
- 《Java基础知识》Java锁详解(volatile,synchronized等)
volatile: 让变量每次在使用的时候,都从主存中取. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执 ...
- linux基础知识3_根文件系统详解
文件系统: rootfs:根文件系统 /boot:系统启动相关的文件,如内核.initrd以及grub /dev:设备文件 块设备:随机访问 字符设备:线性访问,按字符为单位 设备号:主设备号(maj ...
- JavaScript基础知识之——Location 对象详解
属性 描述 location.hash 设置或取得 URL 中的锚 location.host 设置或取得 URL 中主机(包括端口号) location.hostname 设置或取得 URL 中的主 ...
- vue.js基础知识篇(2):指令详解
第三章:指令 1.语法 指令以v-打头,它的值限定为绑定表达式,它负责的是按照表达式的值应用某些行为到DOM上. 内部指令有v-show,v-else,v-model,v-repeat,v-for,v ...
- 《Java基础知识》Java字符串详解
本文内容: String类的概述 String类的使用步骤 String类的常用方法 本文目的: 能够使用String类的构造方法创建字符串对象 能够明确String类的构造方法创建对象,和直接赋值创 ...
- 《Java基础知识》Java异常处理详解
1. Java 中的异常 前言:Java 中的异常处理是处理程序运行错误时的强大机制之一,它可以保证应用程序的正常流程. 首先我们将了解java异常.异常的类型以及受查和非受查异常之间的区别. 1.1 ...
- 《Java基础知识》Java 泛型详解
JDK 1.5 之后,Java 通过泛型解决了容器类型安全这一问题,而几乎所有人接触泛型也是通过Java的容器.那么泛型究竟是什么? 泛型的本质是参数化类型:也就是说,泛型就是将所操作的数据类型作为参 ...
随机推荐
- 原生php导出csv文件
require('./db/dbManager.php'); require('./session.php'); require('./department_utils.php'); class Ex ...
- 后端工程师必知必会的前端 css 知识
后端工程师虽然大部分工作都是跟服务器缓存数据库打交道,但有时也需要写一些前端代码. 有些公司的OAM后台基本是由后端工程师承包的,所以前端基础知识是必须要掌握的:就算开发中不直接写前段代码,了解前端知 ...
- 前端每日实战:55# 视频演示如何用纯 CSS 创作一个太阳、地球、月亮的运转模型
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/RJjQYY 可交互视频 此视频是可 ...
- JZOJ 3526. 【NOIP2013模拟11.7A组】不等式(solve)
3526. [NOIP2013模拟11.7A组]不等式(solve) (File IO): input:solve.in output:solve.out Time Limits: 1000 ms M ...
- 如何开发和发布一个Vue插件
前言 Vue 项目开发过程中,经常用到插件,比如原生插件 vue-router.vuex,还有 element-ui 提供的 notify.message 等等.这些插件让我们的开发变得更简单更高效. ...
- 数据库介绍以及MySQL数据库的使用
一 数据库介绍 1.1 数据库定义 数据库就是存储数据的仓库 本质上就是一套cs结构的TCP程序 客户端连接到服务器 向服务器发送指令 完成数据的操作 1.2 常见数据库 关系型数据库 就是 ...
- Thead基础及两种创建方式
今天本人给大家讲解一下多线程,如有不对的或者讲的不好的可以多多提出,我会进行相应的更改,先提前感谢提出意见的各位了!!! 说说多线程本人自己对它理解的定义:因计算机的CPU支持能够在同一时间执行多于一 ...
- video标签加载视频有声音却黑屏
问题 昨天用户上传了一个视频文件,然而发现虽然有声音但是黑屏. 解释 因为原视频的编码是用 mp4v 格式的,它需要专用的解码器.而 chrome 并不支持,所以无法播放. 然后如果用转码功能转成用 ...
- JS的3种核心设计模式
一.单例模式 1.保证一个类仅有一个实例,并提供一个访问它的全局访问点 2.设计思路:如果存在,不创建,直接返回,不存在才创建. 在类的constructor方法里添加一个判断条件属性,并且让创建的实 ...
- mongo的聚合操作
对图7-1所示的数据集exampledata1,使用聚合操作实现以下功能: (1)不返回_id字段,只返回age和sex字段. (2)所有age大于28的记录,只返回age和sex. (3)在$mat ...