专栏首页不做码农的开发者C# 基础知识系列- 6 Lambda表达式和Linq简单介绍

C# 基础知识系列- 6 Lambda表达式和Linq简单介绍

前言

C#的lambda和Linq可以说是一大亮点,C#的Lambda无处不在,Linq在数据查询上也有着举足轻重的地位。

那么什么是Linq呢,Linq是 Language Intergrated Query(语言集成查询)的缩写,可以对本地对象集合或者远程数据源进行结构化的查询操作。

那什么又是Lambda呢?嗯,简单来讲就是匿名函数,我们不声明方法名,只写一个方法体,这个方法体就是lambda表达式

lambda表达式

如何写一个lambda表达式

首先,在写lambda表达式之前,需要先了解 两个特殊的类型:FuncAction

这是两个委托,这里先不急着了解什么是委托,可以把它们当做一种名称规范就行,它们都可以表示一个方法。不同的是其中Func表示一个有返回值的方法,Action表示一个没有返回值的方法。C#对这两个的定义如下:

public delegate TResult Func<out TResult>();//注意这里的out 表示这个泛型是返回值的类型泛型
public delegate void Action();

其中FuncAction各有16个变种:

// 注意 in 关键字,表示泛型是参数的类型约束
public delegate TResult Func<in T,out TResult>(T arg);
public delegate TResult Func<in T1,in T2,out TResult>(T1 arg1, T2 arg2);
……
public delegate TResult Func<in T1,in T2,in T3,in T4,in T5,in T6,in T7,in T8,in T9,in T10,in T11,in T12,in T13,in T14,in T15,in T16,out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
//
//

public delegate void Action<in T>(T obj);
public delegate void Action<in T1,in T2>(T1 arg1, T2 arg2);
……
public delegate void Action<in T1,in T2,in T3,in T4,in T5,in T6,in T7,in T8,in T9,in T10,in T11,in T12,in T13,in T14,in T15,in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

依次表示一个参数、两个参数、……十六个参数 的方法。当然,你还可以写更多的参数,但是如果一个方法的参数超过10个,为什么不用类封装起来呢?即使不封装,一个方法十几个参数,你确定不会被你的领导嫌弃吗。

言归正传,介绍完了FuncAction的定义,那么如果使用呢?

public void Demo1(){
    // 一个没有返回值,也没有参数的方法
}

Action act1 = Demo;// 直接给一个方法名

public void Demo2(string name){
    //有一个参数,但没有返回值的方法
}

Action<string> act2 = Demo2;

public String Demo3(){
    // 有返回值,但没有参数的方法
}
Func<string> func1 = Demo3;

public int Demo4(double data){
    // 返回值是int,有一个参数是double的方法
}

Func<double,int> func2 = Demo4;

以上是通过方法名获取FuncAction的方法,下面介绍一下通过Lambda表达式的方式创建FuncAction

Action act1 = ()=> // lambda 的标志性 声明方式 =>
{
    // 这是一个没有返回值,也没有参数的 lambda表达式
};
Action<int> act2 = (age) => 
{
    // 这是一个 参数为int ,没有返回值的 lambda表达式
};
//=========================================
Func<string> func1 = () => ""; // 这是一个返回了空字符串的lambda表达式,注意这种写法
Func<string> func2 = () =>
{
    return ""; //与上一个等价
}

Func<int,string> func3 = (age) =>
{
    return "我的年纪是:"+age;// 一个参数是int,返回类型是string的lambda表达式
}

在lambda表达式中,当使用的是有返回值的方法体时,如果方法体是个简单的计算式或者说可以在一行内写完(或被编译器认为是一行)的话,可以省略 {}return,直接用 => 标记。

比如说以下内容:

Func<int,int,int> cal_area = (width, height) => width * height;// 计算面积

使用Lambda 表达式

现在我们手里有一大堆的ActionFunc,我们该怎么用呢?

有以下两种常见的用法:

  1. 把它当做方法来用: // 上接上文代码 act1();// 执行 act1 代表的方法或lambda表达式 act2(10); //执行act2 的lambda表达式 string str1 = func1(); string str2 = func3(10); int area = cal_area(29,39);
  2. 调用Invoke方法: act1.Invoke(); act2.Invoke(10); area = cal_area.Invoke(33,63); 看过反射篇的应该对Invoke有一定印象,这个与MethodInfo里的Invoke类似,但是比其更加简单。

Linq 是什么

正如前言所述,Linq是一种对集合、数据源的集成式查询方式,它是对IEnumerable<T>的扩展方法集,所以想要使用Linq的话,需要引用两个命名空间 System.LinqSystem.Linq.Expressions

Linq有两种使用方式,一种是通过方法链的方式调用,一种是类似SQL语句的方式进行数据查询。方法链是基础,类SQL方式是语法糖。下面简单介绍一下两种方式的使用,不过首先先假设我们有一个数据很多的集合:

IEnumerable<int> scores = new List<int>();//假设存放了某班50个人的语文成绩

使用方法链查询

  1. 获取分数大于60的所有分数: IEnumerable<int> result1 = scores.Where(t => t > 60);
  2. 获取分数大于等于60的数量: int count = scores.Count(t => t >= 60);
  3. 统计分数总和 int sum = scores.Sum();
  4. 获取所有分数个位上的数字: IEnumerable<int> result2 = scores.Select(t => t % 10);

使用类SQL形式查询

查询所有大于等于60的分数:

IEnumerable<int> result3 = from score in scores
                where score >= 60
                select score;

简单介绍一下,类SQL形式有一个统一的格式写法,关键字frominselect缺一不可:

from 临时变量名 in 数据源 select 结果类型

where 是条件过滤,如果查询全部,可以忽略。

这种方式之所以被我称为是类SQL形式,是因为它的写法和SQL及其相似,熟悉SQL的可以很快上手。

为什么说方法链是基础呢?

因为SQL形式的查询里每一个关键字背后都有一个方法作为支撑,除了from 和in。

select 对应的Select 方法,where对应的Where方法。

需要特别注意的一点:

Linq查询是一种延迟查询,也就是说当返回类型是一个IEnumerable 的时候不会立即返回结果,必须调用ToList才能获取到实际查询结果。另外需要注意的是,ToList返回的是一个不可变List集合,这一点在集合篇中做过介绍了。

未完待续

C#里的Linq内容如此丰富,以至于一时间无法详细说明,后续还会有两到三篇关于Linq的内容,今天就先到这里了,感谢您的阅读。

本文分享自微信公众号 - 不做码农的开发者(attachie_1),作者:高先生工作室

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【asp.net core 系列】9 实战之 UnitOfWork以及自定义代码生成

    在前一篇中我们创建了一个基于EF的数据查询接口实现基类,这一篇我将带领大家讲一下为这EF补充一些功能,并且提供一个解决避免写大量配置类的方案。

    程序员小高
  • C# 数据操作系列 - 4. 自己实现一个ORM

    在之前的几篇内容中,我们了解了如何通过ADO.NET 访问数据库,如何修改、新增数据。如何通过DataSet和DataAdapter获取数据,我们将在这一篇试试...

    程序员小高
  • 【asp.net core】7 实战之 数据访问层定义

    在上一篇,我们搭建了一个项目框架,基本上是一个完整的项目。目前而言,大部分的应用基本都是这个结构。好的,不废话了,进入今天的议题:完成并实现数据层的基础实现。

    程序员小高
  • 1000 Genome Project

    1000 Genome Project 的目标是发现在人群中频率大于1%的变异位点,对来自不同人群的大量样本进行测序,识别到了许多的变异位点,为人类遗传变异的研...

    生信修炼手册
  • Python 爬取 B 站,宋智孝李光洙哪个更受宠?

    在中国,大家应该都了解《跑男》这个节目吧,跑男这个节目就是引用了韩国的《Running Man》,成员组成包括原六位成员刘在石、池石镇、金钟国、HAHA(河东勋...

    一墨编程学习
  • Python2运行时查看线程信息

    kongxx
  • IDEA 无法运行Junit, 报错Class not found xxxx Empty test suite.

    网上搜了一圈没找到答案, 最后才发现是因为testmodule没有把class编译到主代码编译的路径. ?

    用户1216491
  • NBA球员投篮数据可视化。

    小F
  • PHP获取客户端浏览器类型与版本函数封装应用

    实现: /**  * 获取客户端浏览器类型  * @param  string $glue 浏览器类型和版本号之间的连接符  * @return string|...

    Sindsun
  • NBA球员投篮数据可视化分析

    用户2769421

扫码关注云+社区

领取腾讯云代金券