关键词:
要想学好linq to object 我们必须要先学习lambda 表达式,学习lambda 表达式呢我们必须了解匿名函数和匿名类及扩展方法,学习匿名函数,我们必须学会委托,这是本文的宗旨。下面开始第一步。在第一步开始之前,我们做点准备工作,建立一个学生类和一个班级类,类结构如下
public class Student public int Id get; set; public int ClassId get; set; public string Name get; set; public int Age get; set; public void Study() Console.WriteLine("0 1跟着Eleven老师学习.net高级开发", this.Id, this.Name); public class Class public int Id get; set; public string ClassName get; set;
在准备一个基础数据类
public class LinqShow /// <summary> /// 准备数据 /// </summary> /// <returns></returns> public List<Student> GetStudentList() #region 初始化数据 List<Student> studentList = new List<Student>() new Student() Id=1, Name="打兔子的猎人", ClassId=2, Age=35 , new Student() Id=1, Name="Alpha Go", ClassId=2, Age=23 , new Student() Id=1, Name="白开水", ClassId=2, Age=27 , new Student() Id=1, Name="狼牙道", ClassId=2, Age=26 , new Student() Id=1, Name="Nine", ClassId=2, Age=25 , new Student() Id=1, Name="Y", ClassId=2, Age=24 , new Student() Id=1, Name="小昶", ClassId=2, Age=21 , new Student() Id=1, Name="yoyo", ClassId=2, Age=22 , new Student() Id=1, Name="冰亮", ClassId=2, Age=34 , new Student() Id=1, Name="瀚", ClassId=2, Age=30 , new Student() Id=1, Name="毕帆", ClassId=2, Age=30 , new Student() Id=1, Name="一点半", ClassId=2, Age=30 , new Student() Id=1, Name="小石头", ClassId=2, Age=28 , new Student() Id=1, Name="大海", ClassId=2, Age=30 , new Student() Id=3, Name="yoyo", ClassId=3, Age=30 , new Student() Id=4, Name="unknown", ClassId=4, Age=30 ; #endregion return studentList;
简单了解委托
1. 委托是什么?
其实,我一直思考如何讲解委托,才能把委托说得更透彻。说实话,每个人都委托都有不同的见解,因为看问题的角度不同。个人认为,可以从以下2点来理解:
(1) 从数据结构来讲,委托是和类一样是一种用户自定义类型。
(2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象。
既然委托是一种类型,那么它存储的是什么数据?
我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。
2. 委托类型的定义
委托是类型,就好像类是类型一样。与类一样,委托类型必须在被用来创建变量以及类型对象之前声明。
delegate void MyDel(int x);
委托类型声明:
(1) 以deleagate关键字开头。
(2)返回类型+委托类型名+参数列表。
3. 声明委托变量
MyDel del1,del2;
4. 初始化委托变量
(1) 使用new运算符
new运算符的操作数的组成如下:
- 委托类型名
- 一组圆括号,其中包含作为调用列表中的第一个成员的方法的名字。方法可以是实例方法或静态方法。
del1 = new MyDel( 实例方法名 ); del2 = new MyDel( 静态方法名 );
(2)使用快捷语法
快键语法,它仅由方法说明符构成。之所以能这样,是因为在方法名称和其相应的委托类型之间有隐式转换。
del1 = 实例方法名; del2 = 静态方法名;
5. 赋值委托
由于委托是引用类型,我们可以通过给它赋值来改变包含在委托变量中的方法地址引用。旧的引用会被垃圾回收器回收。
MyDel del; del = 实例方法名; //委托初始化 del = 静态方法名;//委托重新赋值,旧的引用将被回收
6. 委托调用
委托调用跟方法调用类似。委托调用后,调用列表的每个方法将会被执行。
在调用委托前,应判断委托是否为空。调用空委托会抛出异常,这是正常标准调用
if(null != del) del.Invoke();//委托调用
在net 1.1的时代,我们是使用Invoke()方法类调用委托的。但是微软在net 2.0 的时候,我们可以这么去调用委托 直接 del();
if(null != del) del();//委托调用
7. 综合练习
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Test class Program public delegate void meathed1();//1 委托的声明 委托是一种类型 public delegate int meathed2();//2 可以声明在类的内部,也可以声明在类的外部 public delegate void meathed3(int id, string name); public delegate string meathed4(string msg); static void Main(string[] args) meathed1 me1 = new meathed1(m1); meathed2 me2 = new meathed2(m2); meathed3 me3 = new meathed3(m3); meathed4 me4 = new meathed4(m4); me1.Invoke(); int result= me2.Invoke(); Console.WriteLine(result); me3(1, "wbc"); Console.WriteLine(me4("您吃了吗")); Console.Read(); public static void m1() Console.WriteLine("我是无参数无返回值的方法"); public static int m2() Console.WriteLine("我是无参数有返回值的方法~~~~~~~~~"); return 123; public static void m3(int id, string name) Console.WriteLine($"我是有参数无返回值的方法,id=id,name=name"); public static string m4(string sparams) Console.WriteLine($"我是无参数无返回值的方法 ,参数sparams"); return "参数返回了";
8. 多播委托
多播委托(MulticastDelegate)继承自 Delegate ,表示多路广播委托;即,其调用列表中可以拥有多个元素的委托。实际上,我们自定义的委托的基类就是 MulticastDelegate。这句话不好理解,继续往下看
当我们自己写一个类去继承Delegate 的时候,开发工具提示我 特殊类型不允许被继承,估计这是net 唯一一个特殊类型。
public abstract class myted : Delegate
我们来看一个案列来使用下多播委托
meathed1 me1 = new meathed1(m1); me1 += m2; me1 += m3; me1.Invoke(); me1 -= m2; me1();
多播委托:
+= 的时候就是在委托的实例之后加入注册更多的方法,像一个链子,执行的时候按加入的先后顺序执行
-=的时候就是在委托的实例之后移除注册更多的方法。从链子的尾部开始匹配,找到一个完全吻合的移除,没有找到不会触发异常。
注:实例方法因为每一次实例地址的引用不一致,所以无法移除。
9. net 框架提供的自带委托
8.1.Func委托类型
Func是有返回值的泛型委托,可以没有参数,但最多只有16个参数,并且必须要有返回值。
Func<string, int> funcDelegate = new Func<string, int>();
2.Action委托类型
Action是没有返回值的泛型委托,可以没有参数,但最多只有16个参数。
Action<string, string> method = new Action<string, string>();
关于泛型这里就不过多介绍了,本人前边写了一篇比较详细。建议大家以后使用委托的时候,尽量使用net 类库自带的委托。
这里扩展下事件的基本使用,事件就是在委托的实例加上一个event 的关键字。所以委托是一种类型,事件就是委托类型的实例。这里只是扩展,不懂不影响学习linq to object
public void Meta() public delegate void meathed1(); public class Cat public event meathed1 met_event; public meathed1 mea = new meathed1(m1); public void Run() mea += m2; mea.Invoke(); met_event = new meathed1(m1); met_event += m2; met_event.Invoke(); public static void m1() public static void m2()
调用方法如下
Cat c = new Cat(); c.mea = Meta; c.mea.Invoke(); // c.met_event = meta;这种写法是不允许的,只有通过订阅的方式才允许,如下 c.met_event += new meathed1(Meta);
使用事件和委托的区别我们一下子就能区分出来:事件更安全,在类的外部不允许破坏他的原有执行内容,只有在从新订阅 event关键字限制了权限,保证安全
匿名方法&lambda表达式
我们看了上面的委托,发现写起来好麻烦,并且用起来特别的不方便,有没有更简便的方法呢?可不可以把我们的方法写到委托里面呢?答案是肯定的;这种写法我们称为匿名方法。写法如下:
Action<string> method = new Action<string>(delegate(string name) Console.WriteLine(name); ); method.Invoke("wbc"); Console.Read();
但是这种写法还不够简便,在.net 2.0的时候,我们发现1.1的时候在频繁的使用委托,微软做了很大的改进和更新,新的写法如下
Action<string> method = new Action<string>(name => Console.WriteLine(name) ); method.Invoke("wbc"); Console.Read();
在2.0里面,我们去掉了delegate关键字,如果子有一个参数的时候,连括号也省略了,用"=>"指向方法体,这个尖叫号等号我们读做“goes to”,如果方法只有一句话,连花括号也省略了。参数类型直接就可以推算出来。看一个复杂的案列
Func<string,int,string> method = new Func<string, int, string>((name,age) => return $"name今年age岁了"; ); string result= method.Invoke("wbc",0); Console.WriteLine(result); Console.Read();
其实我们的匿名方法就是lambda 表达式。
匿名类
有了匿名方法一定会有匿名类,在net 3.0的时候才有的匿名类,我们看下在没有匿名类的时候,我们是如何去写的。
object student = new id=123, name="1234" ; Console.WriteLine(student); Console.Read();
这种写法只能输出 “ id = 123, name = 1234 ”这种结果的Json 数据,并且我们在程序中不能使用student.id,会报错。看下匿名写法
var model = new Id = 1, Name = "Alpha Go", Age = 21, ClassId = 2 ; Console.WriteLine(model.Age); Console.Read();
我们来看下var 关键字,其实var 关键字就是一个语法糖,我们不必过于在意,这里就不过多的演示了,我们的根本目的是linq to object
1. 必须在定义时初始化。也就是必须是var s = “abcd”形式,而不能是如下形式:
var s;
s = “abcd”;//这种写法是不允许的
2. 一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。
3. var要求是局部变量。
4. 使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样。
这里在简要扩展点技术点“dynamic”,dynamic的用法和object差不多,区别是dynamic在编译的时候才声明的一个类型,但是本人建议在程序开发中尽量避开这个关键字,后续MVC 中在详细介绍,dynamic是net 40里面的关键字。
扩展方法
扩展方法必须建立在静态类中的静态方法,且第一个参数前边要加上this 关键字,使用扩展方法必须引用扩展方法所在的类的命名空间,如果想要全局使用,可以不带命名空间。个人建议程序中的扩展方法尽量要带上命名空间。我们来看下扩展方法的使用
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Test class Program static void Main(string[] args) int? a = null; Console.WriteLine(Helper.ToInt(a));//常规写法输出 Console.WriteLine(a.ToInt());//扩展方法输出 if ("1qazwsx1qazwsx1qazwsx1qazwsx".ToLengthInCount(16)) Console.WriteLine("密码长度应当小于16个字符"); Console.Read(); public static class Helper /// <summary> /// 验证一个数字是否为空,为空返回-1 /// 扩展方法:静态类里的静态方法,第一个参数类型前面加上this /// </summary> /// <param name="iParameter"></param> /// <returns></returns> public static int ToInt(this int? iParameter) return iParameter ?? -1; /// <summary> /// 验证一个字符串长度是否大指定长度 /// /// </summary> /// <param name="sParameter"></param> /// <returns></returns> public static bool ToLengthInCount(this string sParameter, int iCount) return sParameter.Length >= iCount ? true : false;
这里简要说明下,扩展方法的方法名和类内不得方法名相同,会优先选择类内部的方法,这是以就近原则,去执行的,关于就近原则,请看本人java 相关博客,有介绍
linq to object
1. 什么是linq to object ?
LINQ即Language Integrated Query(语言集成查询),LINQ是集成到C#和Visual Basic.NET这些语言中用于提供查询数据能力的一个新特性。linq to object 就是对象查询体系。
注:LINQ(发音为Link)
我们来看一个简单的列子,用到了我们前边准备的两个类。我们要取出学生年龄小于30岁的,我们如果不会linq to object 的写法如下
LinqShow linq = new LinqShow(); List<Student> studentList = linq.GetStudentList();//获取基础数据 List<Student> studentListLessThan30 = new List<Student>(); foreach (var item in studentList) if (item.Age < 30) Console.WriteLine($"name=item.Name,age=item.Age"); studentListLessThan30.Add(item); Console.Read();
我们可不可以使用委托去计算呢??
LinqShow linq = new LinqShow(); List<Student> studentList = linq.GetStudentList();//获取基础数据 List<Student> studentListLessThan30 = new List<Student>(); //Func<Student, bool> predicate = s => s.Age < 30;//写法一, //var list = studentList.Where<Student>(predicate);//linq var list = Enumerable.Where(studentList, s => s.Age < 30);//使用lambda 表达式写法 foreach (var item in list) Console.WriteLine($"Name=item.Name Age=item.Age"); Console.Read();
两段代码我就不比较了,这里我们只来剖析下 studentList 的Where方法,我们可以转移到定义看下,其实where 里面的参数,如下图
我们会发现,这不List<T>自带的一个方法,而是一个扩展方法,这个扩展方法在”System.Linq“命名空间的“public static class Enumerable”类下,也就是说根据扩展方法的特点,我们只要引用了“System.Linq”命名空间,就能使用这个扩展方法,这个扩展方法真的第二个参数是一个Func<TSource, bool> 委托,这个委托有一个TSource泛型参数,一个bool返回值。这就说明了我们上面的lambda 表达式是成立的。
继续剖析,我们接受的时候,没有使用List<Student>接收返回的集合,这是因为我们的linq 只有遇到循环的时候或遇到ToList<T>()的时候才会去迭代,这里涉及到迭代器的问题,后续我们会详细讲解迭代器的使用,或者大家去网上查询下设计模式迭代器。这么说,我们很难理解。我们通过一个案列来分析,自己写一个for 循环的扩展方法,对比下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Test class Program static void Main(string[] args) LinqShow linq = new LinqShow(); List<Student> studentList = linq.GetStudentList();//获取基础数据 //var list = Enumerable.Where(studentList, s => s.Age < 30);//使用lambda 表达式写法, Console.WriteLine($"-------------------------linq写法-----------------------------------"); var list = studentList.Where( s => Console.WriteLine($"我的年龄是s.Age"); return s.Age < 30; );//使用lambda 表达式写法,这里在每一次计算,我们都输出一个我的年龄是,这里不再使用 Enumerable 去调用where ,反正是扩展方法,用法是一样的 foreach (var item in list) Console.WriteLine($"Name=item.Name Age=item.Age"); Console.WriteLine($"-------------------------自定义扩展方法写法-----------------------------------"); var Wbclist = studentList.WbcWhere(s => Console.WriteLine($"Wbc我的年龄是s.Age"); return s.Age < 30; );// 自定义扩展方法写法 这里不再使用 Enumerable 去调用where foreach (var item in Wbclist) Console.WriteLine($"Name=item.Name Age=item.Age"); Console.Read(); public static class Helper /// <summary> /// 自定义扩展方法计算集合 /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="predicate"></param> /// <returns></returns> public static IEnumerable<TSource> WbcWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) //常规情况下数据过滤 List<TSource> studentListLessThan30 = new List<TSource>(); foreach (var student in source) //if (item.Age < 30) if (predicate(student)) studentListLessThan30.Add(student); return studentListLessThan30; /// <summary> /// 验证一个数字是否为空,为空返回-1 /// 扩展方法:静态类里的静态方法,第一个参数类型前面加上this /// </summary> /// <param name="iParameter"></param> /// <returns></returns> public static int ToInt(this int? iParameter) return iParameter ?? -1; /// <summary> /// 验证一个字符串长度是否大指定长度 /// /// </summary> /// <param name="sParameter"></param> /// <returns></returns> public static bool ToLengthInCount(this string sParameter, int iCount) return sParameter.Length >= iCount ? true : false;
我们来看下输入结果
通过执行结果,我们会发现,自定义的扩展方法是循环一遍,统一输出的,没有延迟,而linq 的写法有延迟。这也就是我们linq 核心之一 “linq 是有延迟的”。这里特别说明,linq 的延迟加载和EF ,ORM 的延迟加载,不是一会事,这里说的延迟,指的是当用到某条数据的时候,才会去查询。
2. 高逼格装X时刻
我们以llambda表达式去写linq 称为 查询运算符写法,下边我们 使用 查询表达式去写,注意区分什么是查询表达式,什么是查询运算符写法,我面试的很多人都说反了。
案列一 多条件过滤筛选数据
LinqShow linq = new LinqShow(); List<Student> studentList = linq.GetStudentList();//获取基础数据 //查询运算符 var list1 = studentList.Where<Student>(s => s.Age < 30 && s.Name.Length > 3);//陈述句 foreach (var item in list1) Console.WriteLine("Name=0 Age=1", item.Name, item.Age); //查询表达式 Console.WriteLine("********************"vue一步一步带你封装一个按钮组件(代码片段)#前言本文主要对子组件的封装做一个了解首先我们直接看一下代码显示首先是今天有一个学妹过来问我如何封装子组件#实现效果首先这个组件是基于eleemnt-ui进行封装的我们看一眼实现效果 有了实现效果之后我们一起来看看... 查看详情
面试必备透过源码角度一步一步带你分析arraylist扩容机制(代码片段)
一先从ArrayList的构造函数说起ArrayList有三种方式来初始化,构造方法源码如下:/**默认初始容量大小*/privatestaticfinalintDEFAULT_CAPACITY=10;privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA=;/*默认构造函数,使用初始容量10构造一个空列表... 查看详情
一步一步带你安装史上最难安装的vim插件——youcompleteme
YouCompleteMeisafast,as-you-type,fuzzy-searchcodecompletionengineforVim.参考: https://github.com/Valloric/YouCompleteMe#full-installation-guide本篇文章默认读者知道什么是unix/linux,vim/vi,YouCompleteMe,如果有不清楚的,S 查看详情
android一步一步带你实现recyclerview的拖拽和侧滑删除功能
先上效果图: 本篇文章我们来学习一个开源项目Android-ItemTouchHelper-Demo 这个项目使用了RecyclerView的ItemTouchHelper类实现了Item的拖动和删除功能,ItemTouchHelper是v7包下的一个类,我们看一下他的介绍Thisisautilityclasstoaddswip... 查看详情
一步一步带你反编译apk,并教你修改smali和重新打包
一、工具介绍:1.apktool:aapt.exe,apktool.bat,apktool.jar;三个在同一目录结合使用,用来反编译apk,apk重新打包;2.dex2jar:该工具作用是将classes.dex文件,反编译出源码(如果apk未加固),反编译出文件,使用jd-gui工具进行查看;3.Auto-Sign... 查看详情
公子奇带你一步一步了解java8中lambda表达式
在上一篇《公子奇带你一步一步了解Java8中行为参数化》中,我们演示到最后将匿名实现简写为1(Policepolice)->"浙江".equals(police.getPoliceNativePlace());这是一个带有箭头的函数,这种写法在Java8中即为Lambda表达式。那么我们就来好好... 查看详情
vue3教程:理工直男都是如何一步一步带妹构建插件?(代码片段)
作者:Shadeed译者:前端小智来源:learnvue有梦想,有干货,微信搜索【大迁世界】关注这个在凌晨还在刷碗的刷碗智。本文GitHubhttps://github.com/qq449245884/xiaozhi已收录,有一线大厂面试完整考点、资料以及我... 查看详情
一步两步带你实现android沉浸式设计(代码片段)
前言 沉浸式不知道什么时候有了两种叫法,一种是沉浸式模式,一种是沉浸式状态栏,Google从Android4.4开始,给我们开发者提供了一套透明的系统UI样式给状态栏和导航栏,这样完美的玩法简直和IOS系统媲... 查看详情
从零开始带你一步一步使用yolov3测试自己的数据
上一篇: 从零开始带你一步一步使用YOLOv3训练自己的数据我给大家详细介绍了如何使用YOLOv3模型来训练自己的数据集。训练部分完成,本文将继续给大家详细介绍如何使用我们训练好的模型来进行图片的批量测试。一、... 查看详情
从零开始带你一步一步使用yolov3测试自己的数据(代码片段)
...f1a;AI有道(redstonewill)上一篇:从零开始带你一步一步使用YOLOv3训练自己的数据我给大家详细介绍了如何使用YOLOv3模型来训练自己的数据集。训练部分完成 查看详情
windows系统带你一步一步无脑使用babel
不废话直接写看步骤:1、在F盘新建一个文件夹叫babel2、npminit初始化项目3、全局安装npminstallbabelbabel-cli-g4、项目安装npminstallbabel-cli--save-dev项目目录里会多一个node_modules包5、新建一个es6.js文件随便写一段es66、输入指令babeles... 查看详情
从零开始带你一步一步使用yolov3训练自己的数据(代码片段)
...测(ObjectDection)算法。今天给大家介绍一下如何一步一步使用Y 查看详情
史上最细基于redis实现的分布式session解决单点登录问题,入门导师带你一步一步实现...(代码片段)
...分享一下使用Redis实现分布式session完成单点登录,下一篇与大家分享一下使用Redis实现分布式锁实现定时关单功能,好啦文章干货满满咱们就不多絮叨直接开搞了!需要说明一点就是贴出的代码是自己修改过的& 查看详情
一步一步教你认识闭包
在公众号中曾经介绍过两篇关于函数的文章,第一篇是关于 Python函数是第一类对象,第二篇是关于 Lambda函数,今天来说说Python闭包。什么是闭包?闭包有什么用?为什么要用闭包?今天我们就带着这3个问题来一步一步... 查看详情
linux驱动实践:带你一步一步编译内核驱动程序(代码片段)
作者:道哥,10+年嵌入式开发老兵,专注于:C/C++、嵌入式、Linux。文章目录学习的困惑实践环境编译进内核创建驱动程序目录创建源文件创建Kconfig文件创建Makefile文件编译编译为驱动模块编译所有的驱动... 查看详情
linux驱动实践:带你一步一步编译内核驱动程序(代码片段)
作者:道哥,10+年嵌入式开发老兵,专注于:C/C++、嵌入式、Linux。文章目录学习的困惑实践环境编译进内核创建驱动程序目录创建源文件创建Kconfig文件创建Makefile文件编译编译为驱动模块编译所有的驱动... 查看详情
一个老王开枪案例带你一步一步领略程序开发的魅力(代码片段)
一、前言 我身边的很多同学都认为学计算机专业的人,代码写的好很正常,认为自己不是学计算机专业的,不会写代码很正常,或者这么说,觉得会写代码是一种天赋。其实不然,我们现在必须要清楚当代社会的局势,当代... 查看详情
带你一步一步的解析arouter源码(代码片段)
ARouter是阿里推出的一款页面路由框架。由于项目中采用了组件化架构进行开发,通过ARouter实现了页面的跳转,之前看它的源码时忘了写笔记,因此今天来重新对它的源码进行一次分析。(顺手留下GitHub链接,需要获取相关面试... 查看详情