前言

在上一篇中简单介绍了Linq的入门级用法,这一篇尝试讲解一些更加深入的使用方法,与前一篇的结构不一样的地方是,这一篇我会先介绍Linq里的支持方法,然后以实际需求为引导,分别以方法链的形式和类SQL的形式写出来。

前置概念介绍

  1. Predicate<T> 谓词、断言,等价于 Func<T,bool> 即返回bool的表达式
  2. Expression<TDelegate> 表达式树,这个类很关键,但是在这里会细说,我们会讲它的一个特殊的泛型类型:Expression<Func<T,bool>> 这个在某些数据源的查询中十分重要,它代表lambda表达式中一种特殊的表达式,即没有大括号和return关键字的那种。

我们先准备两个类

  1. 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; }
}
  1. 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> studentsIEnumerable<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详解的更多相关文章

  1. vue.js基础知识篇(6):组件详解

    第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...

  2. 《Java基础知识》Java注解"@"详解

    Java注解含义: Java注解,顾名思义,注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的.Java注解又叫java标注,java提供了一套机制,使得 ...

  3. 《Java基础知识》Java锁详解(volatile,synchronized等)

    volatile: 让变量每次在使用的时候,都从主存中取. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执 ...

  4. linux基础知识3_根文件系统详解

    文件系统: rootfs:根文件系统 /boot:系统启动相关的文件,如内核.initrd以及grub /dev:设备文件 块设备:随机访问 字符设备:线性访问,按字符为单位 设备号:主设备号(maj ...

  5. JavaScript基础知识之——Location 对象详解

    属性 描述 location.hash 设置或取得 URL 中的锚 location.host 设置或取得 URL 中主机(包括端口号) location.hostname 设置或取得 URL 中的主 ...

  6. vue.js基础知识篇(2):指令详解

    第三章:指令 1.语法 指令以v-打头,它的值限定为绑定表达式,它负责的是按照表达式的值应用某些行为到DOM上. 内部指令有v-show,v-else,v-model,v-repeat,v-for,v ...

  7. 《Java基础知识》Java字符串详解

    本文内容: String类的概述 String类的使用步骤 String类的常用方法 本文目的: 能够使用String类的构造方法创建字符串对象 能够明确String类的构造方法创建对象,和直接赋值创 ...

  8. 《Java基础知识》Java异常处理详解

    1. Java 中的异常 前言:Java 中的异常处理是处理程序运行错误时的强大机制之一,它可以保证应用程序的正常流程. 首先我们将了解java异常.异常的类型以及受查和非受查异常之间的区别. 1.1 ...

  9. 《Java基础知识》Java 泛型详解

    JDK 1.5 之后,Java 通过泛型解决了容器类型安全这一问题,而几乎所有人接触泛型也是通过Java的容器.那么泛型究竟是什么? 泛型的本质是参数化类型:也就是说,泛型就是将所操作的数据类型作为参 ...

随机推荐

  1. 大厂面试官最常问的@Configuration+@Bean(JDKConfig编程方式)

    大厂面试官最常问的@Configuration+@Bean(JDKConfig编程方式)   现在大部分的Spring项目都采用了基于注解的配置,采用了@Configuration 替换标签的做法.一 ...

  2. Hexo+github如何搭建博客

    前言 博客有第三方平台,也可以自建,比较早的有博客园.CSDN,近几年新兴的也比较多诸如:WordPress.segmentFault.简书.掘金.知乎专栏.Github Page 等等. 这次我要说 ...

  3. typescript 02 数据类型

    ---恢复内容开始--- 1.数据类型 ts为了使代码更加规范并利于维护,增加了类型校验 提供了以下几种类型 布尔类型 boolean 数字类型 number 字符串类型 string 数组类型 ar ...

  4. vue相关坑

    1:vue 动态加载图片路径报错解决方法,循环遍历图片不显示图片 解决方法:https://www.cnblogs.com/qingcui277/p/8930507.html

  5. python学习-练习题4巩固

    一个数加100后是一个整数的平方,加268后也是一个数的平方,求这个数 分析:这个数加100之后开方是整数,说明int(math.sqrt(a+100))转为整数应该没有小数部分 so:b*b = i ...

  6. SSL/TLS 协议运行机制概述(一)

    SSL/TLS 协议运行机制概述(一) SSL/TLS 发展史 1994年,NetScape 设计了SSL协议(Secure Sockets Layer) 1.0,未正式发布 1995年,NetSca ...

  7. 一起了解 .Net Foundation 项目 No.19

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. Salesforce To ...

  8. javaScript 基础知识汇总(八)

    1.Map Set WeakMap 和WeakSet Map 是一个键值对的集合,主要的方法包括: new Map() 创建Map map.set(key,value)  根据键(key)存储值(va ...

  9. can do / will do / should do 情态动词

    can do = be able to do will do = be going to do should do = ought to do 情态动词 都是表示建议 从这里发现 to do (不确定 ...

  10. Hacker101-CTF | Postbook

    Hacker101-CTF | Postbook mirror王宇阳 水平有限,不足之处还望指教 ^_^ 看看这个一大堆英文介绍 With this amazing tool you can writ ...