C#基础–Lambda 和 LINQ

一、Lambda 的前世今生

在.NetFramewok的不同版本都有不同的样子;在.NetCore下也都是支持的;

1.1 .Netframework1.0/1.1时代

public delegate void NoReturnWithPara(int x, string y);NoReturnWithPara method = new NoReturnWithPara(Study);
method.Invoke(123, "Richard");private void Study(int id, string name)
{Console.WriteLine($"{id} {name} 学习.Net高级班");
}

1.2 .NetFramework2.0

匿名方法 增加了一个delegate关键字, 可以访问到除了参数以外的局部变量

public delegate void NoReturnWithPara(int x, string y);int i =0;
NoReturnWithPara method = new NoReturnWithPara(delegate (int id, string name)
{Console.WriteLine($"{id} {name} 学习.Net高级班");Console.WriteLine(i);    //可以访问到除了参数以外的局部变量 i
});
method.Invoke(123, "Richard");

1.3 .NetFramework3.0 前期

去掉了delegate关键字,添加了一个=> goes to

public delegate void NoReturnWithPara(int x, string y);int i =0;
NoReturnWithPara method = new NoReturnWithPara((int id, string name) =>
{Console.WriteLine($"{id} {name} 学习.Net高级班");Console.WriteLine(i);
});
method.Invoke(123, "Richard");

1.4 .NetFramework3.0 后期

去掉了匿名方法后的参数类型,编译器自动推断来的/编译器提供的便捷功能(语法糖)

public delegate void NoReturnWithPara(int x, string y);int i =0;
NoReturnWithPara method = new NoReturnWithPara((id, name) =>  //编译器自动推断来的/编译器提供的便捷功能(语法糖)
{Console.WriteLine($"{id} {name} 学习.Net高级班");Console.WriteLine(i);
});
method.Invoke(123, "Richard");

如果匿名方法体中只有一行代码,可以省略方法体的大括号:

public delegate void NoReturnWithPara(int x, string y);NoReturnWithPara method = new NoReturnWithPara((id, name) => Console.WriteLine($"{id} {name} 学习.Net高级班"));
method.Invoke(123, "Richard");
public delegate void NoReturnWithPara(int x, string y);NoReturnWithPara method = (id, name) => Console.WriteLine($"{id} {name} 学习.Net高级班");
method.Invoke(123, "Richard");

如果只有一个参数的时候:

Action<string> method = sn => Console.WriteLine($"欢迎{sn} 来到.Net高级班进阶学习");
method.Invoke("牧羊人");

如果有返回值? 如果lambda表达式中只有一行代码,且有返回值,可以省略return;

Func<string> func0 = () => { return "黄大仙" };//如果有返回值? 如果lambda表达式中只有一行代码,且有返回值,可以省略 `大括号` + `return`;
Func<string> func = () => "黄大仙";
Func<int, string> func1 = i => i.ToString();

大家觉得Lambda表达式本质是什么?

多播委托中可以把Lambda表达式+=,但是不能把Lambda表达式-=。因为Lambda表达式其实是一个方法,不同的lambda表达式就是不同的方法。

Lambda的本质是一个方法。

语法糖:编译器提供的便捷功能

二、LINQ

初始化数据

List<Student> studentList = new List<Student>()
{new Student() { Id=1, Name="赵亮", ClassId=2, Age=35 },new Student() { Id=2, Name="再努力一点", ClassId=2, Age=23 },new Student() { Id=3, Name="王炸", ClassId=2, Age=27 },new Student() { Id=4, Name="疯子科学家", ClassId=2, Age=26 },new Student() { Id=5, Name="灭", ClassId=2, Age=25 },new Student() { Id=6, Name="黑骑士", ClassId=2, Age=24 },new Student() { Id=7, Name="故乡的风", ClassId=2, Age=21 },new Student() { Id=8, Name="晴天", ClassId=2, Age=22 }
};

2.1 Linq 扩展方法&表达式

var list = studentList.Where<Student>(s => s.Age < 30); //list里面必然是符合要求的数据;
var list = from s in studentListwhere s.Age < 30select s;   //list里面必然是符合要求的数据;

以上两种都是LINQ。

2.2 linq to object

Linq – Linq to object:就是针对IEnumerable类型数据

​ 1. IEnumerable 类型数据:可以理解为内存中的数据;其实就是把不变的逻辑封装起来,把可变的逻辑封装成委托来传递;

​ 2. IQueryable 类型数据:可以理解成内存数据—来自于数据库的数据;

延伸:

Linq to Sql:就是把打开数据库连接,查询数据(不变的的逻辑),把sql 的拼装(可变的逻辑)

Linq to Xml:把数据解析这类动作封装起来(不变的逻辑), 把数据筛选条件封装成委托来传递(可变的逻辑)

Linq to Redis:把固定的逻辑封装起来,把不变的逻辑封装成委托传递

Linq to Cache:…

Linq to JSON:…

Linq to Everything:…

IQueryable 和 IEnumerable 存在本质的区别:

  1. 使用IQueryable 查询
List<Student> studentList = this.GetStudentList();var query = studentList.AsQueryable();
query.Where(a => a.Age < 30);public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
  1. 使用 IEnumerable 查询
List<Student> studentList = this.GetStudentList();var query = studentList.AsEnumerable();
query.Where(a => a.Age < 30);public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

IEnumerable 传递的是一个委托,而 IQueryable 传递的是一个表达式目录树(数据结构)

现在大家觉得Linq 是什么?

Linq 是一种封装思想,对于用户来说,就把不需要关心内部怎么实现,只需要Linq一下即可;微软之前很推崇这种思想,只让开发者关注自己的核心逻辑,不需要关注内部逻辑,彻底的把开发者变成编程小白;如果大家有经验的话,你会发现像Asp .Net MVC就属于傻瓜式开发,成套的;我们不用去关心原理就可以直接上手。

但是现在又变了,现在有更高的要求,像是Linq to JSON、Linq to Redis等并没有人来封装这些。如果大家有兴趣,可以去尝试封装一下。

2.3 基本查询

var list = studentList.Where<Student>(s => s.Age < 30).Select(s => new{IdName = s.Id + s.Name,ClassName = s.ClassId == 2 ? "高级班" : "其他班"});
var list = from s in studentListwhere s.Age < 30select new{IdName = s.Id + s.Name,ClassName = s.ClassId == 2 ? "高级班" : "其他班"};

Select 方法:

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

**备注:**使用 studentList.Where(s => s.Age < 30) 查询并返回数据后,实际内容还是一个 IEnumerable 的数据。但是接着再使用了Select 做投影的话,里面创建了一个匿名对象,返回的也是一个匿名对象。

2.4 分页

var list = studentList.Where<Student>(s => s.Age < 30)//条件过滤.Select(s => new//投影{Id = s.Id,ClassId = s.ClassId,IdName = s.Id + s.Name,ClassName = s.ClassId == 2 ? "高级班" : "其他班"}).OrderBy(s => s.Id)//排序.ThenBy(s=>s.ClassName)    //多重排序,可以多个字段排序都生效.OrderByDescending(s => s.ClassId)//倒排.Skip(2)//跳过几条.Take(3)//获取几条;

性能怎样?=> 本质其实都是循环;

2.5 分组

var list = from s in studentListwhere s.Age < 30group s by s.ClassId into sgselect new{key = sg.Key,maxAge = sg.Max(t => t.Age)};
var list = studentList.Where(a=>a.Age<30).GroupBy(c => c.ClassId).Select(sg => new{key = sg.Key,maxAge = sg.Max(t => t.Age)});

2.6 内连接 – inner join

var list = from s in studentListjoin c in classList on s.ClassId equals c.Idselect new{Name = s.Name,CalssName = c.ClassName};
var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new{Name = s.Name,CalssName = c.ClassName});

2.7 左连接 – left join

var list = from s in studentListjoin c in classList on s.ClassId equals c.Idinto scListfrom sc in scList.DefaultIfEmpty()select new{Name = s.Name,CalssName = sc == null ? "无班级" : sc.ClassName//c变sc,为空则用};
var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new{Name = s.Name,CalssName = c.ClassName}).DefaultIfEmpty();

三、自定义封装

3.1 针对一个具体类的封装

/// <summary>
/// 如果换个条件怎么办?
/// 使用委托:委托可以把方法当做参数传递;方法其实是逻辑,委托可以把逻辑当做参数传递;
/// 委托:应该是返回值为bool的委托,参数是一个Student
/// </summary>
/// <param name="resource"></param>
/// <returns></returns>
public static List<Student> RichardWhere(this List<Student> resource, Func<Student, bool> func)
{List<Student> list = new List<Student>();foreach (var item in resource){//if (item.Name.Length > 2) //条件的判断其实就是逻辑---动作 //唯一的区别就在与中间这里的条件不一样;if (func.Invoke(item)){list.Add(item);}}return list;
}

3.2 通用–泛型封装

/// <summary>
/// 这就是Linq中where的本质;
/// 1. 是把固定不变的逻辑,封装起来,把可变的逻辑封装成委托来传递
/// 就可以让开发者只需要关注自己的核心业务,其他别的都以LINQ封装
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>
public static List<T> RichardWhere<T>(this List<T> resource, Func<T, bool> func) where T:class
{List<T> list = new List<T>();foreach (var item in resource){//if (item.Name.Length > 2) //条件的判断其实就是逻辑---动作 //唯一的区别就在与中间这里的条件不一样;if (func.Invoke(item)){list.Add(item);}}return list;
}
/// <summary>
/// 有什么好处?
/// 通过接口来扩展,只要实现了这个接口的,都可以使用当前这个扩展方法
/// 相比而言:自然扩展抽象要好一些,扩展性更好
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>public static IEnumerable<T> RichardWhereEnumerable<T>(this IEnumerable<T> resource, Func<T, bool> func) where T : class
{List<T> list = new List<T>();foreach (var item in resource){//if (item.Name.Length > 2) //条件的判断其实就是逻辑---动作 //唯一的区别就在与中间这里的条件不一样;if (func.Invoke(item)){list.Add(item);}}return list;
}

3.3 实际运用

如果是学生类的实现对象的话,3.1 和3.2都是的话下面代码一样,无需任何修改

var list1 = MethodExtension.RichardWhere(studentList, item => item.Age < 30);
var list2 = studentList.RichardWhere(item => item.Age < 30);var list1 = MethodExtension.RichardWhere(studentList, item => item.Name.Length > 2);
var list2 = studentList.RichardWhere(item => item.Name.Length > 2);var list1 = MethodExtension.RichardWhere(studentList, item => item.Id > 1&& item.Name != null&& item.ClassId == 1&& item.Age > 20);
//循环完毕以后,list里面必然是符合要求的数据;
var list2 = studentList.RichardWhere<Student>(item => item.Id > 1&& item.Name != null&& item.ClassId == 1&& item.Age > 20);

四、yield 使用

/// <summary>
/// yield` 必须和 IEnumerable<T> 配合使用,可以做到按需获取
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="resource"></param>
/// <param name="func"></param>
/// <returns></returns>
public static IEnumerable<T> RichardWhereIterator<T>(this IEnumerable<T> resource, Func<T, bool> func) where T : class
{foreach (var item in resource){if (func.Invoke(item)){yield return item;}}return list;
}var list3 = studentList.RichardWhereIterator(item => item.Age < 30);
foreach (var item in list3)
{Console.WriteLine("Name={0}  Age={1}", item.Name, item.Age);
}

yield 必须和 IEnumerable<T> 配合使用,可以做到按需获取;如果返回值换成 List<T> 就会产生报错

按需获取: var list3 = studentList.RichardWhereIterator(item => item.Age < 30); 执行完之后,并没有实质性执行到 RichardWhereIterator 方法内部,直到 foreach (var item in list3) 的时候,才执行到方法体内,而且是循环一次就到 RichardWhereIterator 获取一条数据。

使用yield 的使用,编译器会生成一个泛型的,会有个迭代状态机 [IteratorStateMachine] (属于特性)

C#基础--Lambda和LINQ相关推荐

  1. 第十二节:Lambda、linq、SQL的相爱相杀(1)

    一. 谈情怀  Lambda.Linq.SQL伴随着我的开发一年又一年,但它们三者并没有此消彼长,各自占有这一定的比重,起着不可替代的作用. 相信我们最先接触的应该就是SQL了,凡是科班出身的人,大学 ...

  2. 简单测试lambda和linq查找的性能

    在List泛型中查找一个值(唯一),究竟用哪种方法快点呢.for循环.foreach迭代器.Lambda表达式.Linq语句. 简单的写了一个程序测试一下.思路:构造一个有26843545个int元素 ...

  3. 《C# 语言入门详解(刘铁锰) - 学习笔记 - Lambda表达 / Linq查询》

    Lambda表达 / LINQ查询 文章目录 Lambda表达 / LINQ查询 前言 一.Lambda表达式 二.LINQ查询 前言 Lambda表达式: 匿名方法.inline(内联)方法.(简化 ...

  4. 第十四节:Lambda、linq、SQL的相爱相杀(3)

    一. SQL 开篇 1. where用法 1 #region 封装EF调用SQL语句查询 2 public static List<T> ExecuteQuery<T>(str ...

  5. 第十三节:Lambda、linq、SQL的相爱相杀(2)

    一. Linq开篇 1.Where用法 linq中where的用法与SQL中where的用法基本一致. 1 #region 01-where用法2 {3 //1. where用法4 //1.1 查询账 ...

  6. 理解lambda在linq中的应用

    LinQ是必须学好的一种查询语言,不得不佩服微软的贡献.现阶段要学好Linq必须了解lambda,关于lambda本身,朋友可以找些资料自己看看,我这只是讲下他的本质. lambda本质上是一个委托, ...

  7. Java基础-Lambda表达式基础练习

    Lambda表达式基础练习 Lambda表达式得格式:(形式参数)->{代码块} Lambda表达式使用前提: 有一个接口 接口中有且仅有一个抽象方法 练习1:定义一个接口(Eatable),里 ...

  8. Lambda表达式 Linq SQL Server 分组后获取第一条数据或最小(最大)数据

    1.Lambda表达式 以下是从网上粘贴下来  经测试失败 提示方法"First"只能用作最终查询操作.请考虑在这个实例中使用方法"FirstOrDefault" ...

  9. 「 Java基础-Lambda 」试试Lambda表达式?通俗易懂得嘞

    前言 Lambda表达式是JDK8的一个新特性,可以取代大部分的匿名内部类,写出更优雅的Java代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构. JDK也提供了大量的内置函数式接口供我 ...

最新文章

  1. FastAdmin扩展PHPEXCEL,PHP7.3高版本兼容问题
  2. (转)oracle extent
  3. 使用 class-dump 扫描 app 关键字
  4. java添加时间,如何通过Java中的addHours()方法添加时间
  5. C++——《算法分析与设计》实验报告——贪心算法与回溯法
  6. SAP Spartacus的发布方式以及语义化版本管理机制
  7. leetcode13
  8. 2017年Spring发布了30个新的Android库,值得您关注
  9. 酷动网博客整站源码+Panda PRO主题+7000条完整数据
  10. [java核心外篇]__Object类与对象类型的转型
  11. java mediator模式_Java实现中介者模式-Mediator Pattern
  12. 1000行代码入门python-Python基础知识和工作环境
  13. 第四章节 窗体应用(Form窗体)
  14. 设计模式六大原则,你真的懂了吗?
  15. java 中float所占字节_Java语言中,float类型所占存储空间为【】个字节
  16. 时间序列平稳性的判断
  17. VLAN端口类型(access、Trunk、Hybrid)
  18. imx6ul之OpenWRT中使用mpd作为音频Server及其使用
  19. 判断三个老师教哪门课命题c语言,教师招聘考试真题7-2013年郑州市高新区
  20. 帆软 html页面,帆软报表-web页面集成

热门文章

  1. 屏幕适配中的dip与px之间的转化
  2. Linux基础 个人VPS安全
  3. redis.windows-service.conf和redis.windows.conf的区别
  4. 业务中立_反对网络中立性威胁开源社区的生存
  5. BugKu-CTF(解密篇Crypto)---道友不来算一算凶吉?
  6. Vvivo仿原声Android主题,Android 仿vivo的SeekBar样式
  7. openstack 更改分配IP
  8. 个人题库--不怕万人阻挡,就怕自己投降
  9. springBoot配置视图解析器
  10. 从百播大战到倒闭潮 2017年直播行业该往哪走?