C#基础--Lambda和LINQ
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 存在本质的区别:
- 使用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);
- 使用 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相关推荐
- 第十二节:Lambda、linq、SQL的相爱相杀(1)
一. 谈情怀 Lambda.Linq.SQL伴随着我的开发一年又一年,但它们三者并没有此消彼长,各自占有这一定的比重,起着不可替代的作用. 相信我们最先接触的应该就是SQL了,凡是科班出身的人,大学 ...
- 简单测试lambda和linq查找的性能
在List泛型中查找一个值(唯一),究竟用哪种方法快点呢.for循环.foreach迭代器.Lambda表达式.Linq语句. 简单的写了一个程序测试一下.思路:构造一个有26843545个int元素 ...
- 《C# 语言入门详解(刘铁锰) - 学习笔记 - Lambda表达 / Linq查询》
Lambda表达 / LINQ查询 文章目录 Lambda表达 / LINQ查询 前言 一.Lambda表达式 二.LINQ查询 前言 Lambda表达式: 匿名方法.inline(内联)方法.(简化 ...
- 第十四节:Lambda、linq、SQL的相爱相杀(3)
一. SQL 开篇 1. where用法 1 #region 封装EF调用SQL语句查询 2 public static List<T> ExecuteQuery<T>(str ...
- 第十三节:Lambda、linq、SQL的相爱相杀(2)
一. Linq开篇 1.Where用法 linq中where的用法与SQL中where的用法基本一致. 1 #region 01-where用法2 {3 //1. where用法4 //1.1 查询账 ...
- 理解lambda在linq中的应用
LinQ是必须学好的一种查询语言,不得不佩服微软的贡献.现阶段要学好Linq必须了解lambda,关于lambda本身,朋友可以找些资料自己看看,我这只是讲下他的本质. lambda本质上是一个委托, ...
- Java基础-Lambda表达式基础练习
Lambda表达式基础练习 Lambda表达式得格式:(形式参数)->{代码块} Lambda表达式使用前提: 有一个接口 接口中有且仅有一个抽象方法 练习1:定义一个接口(Eatable),里 ...
- Lambda表达式 Linq SQL Server 分组后获取第一条数据或最小(最大)数据
1.Lambda表达式 以下是从网上粘贴下来 经测试失败 提示方法"First"只能用作最终查询操作.请考虑在这个实例中使用方法"FirstOrDefault" ...
- 「 Java基础-Lambda 」试试Lambda表达式?通俗易懂得嘞
前言 Lambda表达式是JDK8的一个新特性,可以取代大部分的匿名内部类,写出更优雅的Java代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构. JDK也提供了大量的内置函数式接口供我 ...
最新文章
- FastAdmin扩展PHPEXCEL,PHP7.3高版本兼容问题
- (转)oracle extent
- 使用 class-dump 扫描 app 关键字
- java添加时间,如何通过Java中的addHours()方法添加时间
- C++——《算法分析与设计》实验报告——贪心算法与回溯法
- SAP Spartacus的发布方式以及语义化版本管理机制
- leetcode13
- 2017年Spring发布了30个新的Android库,值得您关注
- 酷动网博客整站源码+Panda PRO主题+7000条完整数据
- [java核心外篇]__Object类与对象类型的转型
- java mediator模式_Java实现中介者模式-Mediator Pattern
- 1000行代码入门python-Python基础知识和工作环境
- 第四章节 窗体应用(Form窗体)
- 设计模式六大原则,你真的懂了吗?
- java 中float所占字节_Java语言中,float类型所占存储空间为【】个字节
- 时间序列平稳性的判断
- VLAN端口类型(access、Trunk、Hybrid)
- imx6ul之OpenWRT中使用mpd作为音频Server及其使用
- 判断三个老师教哪门课命题c语言,教师招聘考试真题7-2013年郑州市高新区
- 帆软 html页面,帆软报表-web页面集成
热门文章
- 屏幕适配中的dip与px之间的转化
- Linux基础 个人VPS安全
- redis.windows-service.conf和redis.windows.conf的区别
- 业务中立_反对网络中立性威胁开源社区的生存
- BugKu-CTF(解密篇Crypto)---道友不来算一算凶吉?
- Vvivo仿原声Android主题,Android 仿vivo的SeekBar样式
- openstack 更改分配IP
- 个人题库--不怕万人阻挡,就怕自己投降
- springBoot配置视图解析器
- 从百播大战到倒闭潮 2017年直播行业该往哪走?