委托、事件、lambda表达式
Delegates:是一个对象,知道如何调用一个方法
1> 委托类型:定义了委托实例可以调用的那类方法(它定义了方法的返回类型和参数)
Eg:delegate int Transformer (int x);
int:返回类型为int
Transformer:委托名称
int x:参数X为int类型
static int Square (int x) { return x*x ; }
static int Square (int x) => x*x ;
2> 委托实例:把方法赋给委托变量的时候创建了委托实例
Eg:Transformer t = Square;
Transformer:委托类型
t:委托变量
Square:方法名
委托实例调用方法:int answer = t(3); return:9
t:委托变量
3:参数x
3> 多播委托:所有的委托实例都具有多播功能,一个委托实例可以引用一组目标方法
使用 + 或者 += 操作符可以合并委托实例
使用 - 或者 -= 操作符可以移除委托实例
- 委托式不可变的,使用操作符实际上是创建了一个新的委托实例并把它赋值给了当前的委托变量。
- 如果多播委托的返回类型不是void ,它只会返回最后一个被调用的方法返回值进行返回,之前的会被弃用。
- 所有的委托类型都派生于System.MulticastDelegate,而它又派生于System.Delegate。
- C# 会把作用于委托的 + - += -+ 操作编译成System.Delegate的Combine和Remove两个静态方法。
4> 实例方法目标与静态方法目标:
- 当一个实例方法Square() 赋值给委托对象t 时,t不仅要保留着方法的引用还要保
留着方法所属实例的引用。
- System.Delegate 的 Target 属性就代表着这个实例,如果引用的是静态方法那么
Traget属性值是 null。
5> 泛型委托类型:委托类型是可以包含泛型类型参数的
6> 委托和接口:委托可以解决的问题,接口都可以解决。
7> 什么情况下更适合使用委托:
(1) :接口只能定义一个方法
(2) :需要多播功能
(3) :需要多此实现该接口
8> 委托的兼容性---委托类型:委托类型之间互不兼容,即使方法签名形同(返回类型相同,参数个数相同,参数类型相同)
9> 委托的兼容性---委托实例:如果委托实例拥有相同的方法目标,那么委托实例就认为是相等的。
10> 委托的兼容性---委托参数:委托可以接受比它方法更具体的参数类型,委托定义string类型,方法定义object类型没问题。
11> 委托的兼容性---返回类型:方法可以接受比它委托更具体的返回结果,委托定义object类型,方法定义string类型没问题。
Events:在委托前加一个 event 关键字
- 委托目标方法返回类型必须是 void,
- 可以接受两个参数,第一个参数类型是 object类型(事件的广播者),第二个参数是 EventArgs的子类(包含需要传递的信息)
- 委托名称必须以EventHandler结尾
- 可以出发事件的方法:必须是protected virtual方法,前面在加上on,接受一个是 EventArgs参数
非泛型EventHandler:当时间不携带多余信息时,可以使用非泛型EventHandler。
事件访问器:是事件 +=、 -=函数的实现
Lambda Expressions:
捕获外部变量:可以引用本地变量以及所在方法的参数
闭包:捕获了外部变量的表达式
被捕获的变量在委托被实际调用的时候才会进行计算,而不是在捕获的时候
int factor = 2;
Func<int,int> multiplier = n => n*factor;
factor = 10;
Console.Writeline(multiplier(3)); // 30 而不是 6
Lambda表达式本身可以更新被捕获的变量
int seed = 0;
Func<int> natural = () => seed++;
Console.WriteLine(natural()); // 0 先返回 seed再进行 ++运算
Console.WriteLine(natural()); // 1
Console.WriteLine(seed); // 2
被捕获的变量的生命周期延长到和委托一样
static Func<int> Natual()
{
Int seed = 0;
Return () => seed++;
}
Static void Main()
{
Func<int> natual = Natual(); // seed 变量被捕获住了,生命周期延长
Console.WriteLine(natual()); // 0
Console.WriteLine(natual()); // 1
}
匿名方法:需要指明参数类型、表达式语法只能是语句块、不支持编译表达式树的能力
Delegate int Trans(int i);
Trans sqr = delegate(int x){ return x*x ;};
进程:程序在服务器运行时占据的计算资源集合称之为进程
进程之间不会相互干扰
进程之间的通信比较困难(分布式)
线程:程序执行的最小单位(响应操作的最小的执行流),线程也包含自己的计算资源
线程属于进程、
多线程:一个进程里面有多个线程在并发执行。不卡界面(主线程很快执行完成后闲置)
多线程Thread:实际上就是一个类,就是一个封装,是.net fm对线程对象的抽象封装。
通过Tread去完成的操作,最终是通过操作系统请求得到的执行流。
发短信/写日志/发邮件 可用
CurrentThread:当前线程(任何操作的执行都是线程完成的,运行当前这句话的线程)
ManagedThreadId:是.net平台给Thread起的名字,就是个int值
ThreadPool:线程池
异步和多线程区别与联系:查找
任何的异步多线程都离不开委托 delegate
异步多线程:发起调用,不等待结束就直接进行下一行,动作会由一个新的线程执行(子线程):并发了。执行代码执行的快(资源换性能,占用更多的资源换取更多的性能),单线程慢,但是线程不是越多越好。
线程的无序性:不可预测性
- 启动无序:启动时线程不一定按照01234执行。几乎同一时间向操作系统请求线程,也是需要cpu处理的请求,因为线程时操作系统资源,CLR只能去申请,谁先被处理就得看运气了。
- 执行时间不确定:即使同一个线程同一个任务耗时也有可能不同(跟操作系统的调度策略有关;CPU分片(计算能力太强,1s分拆1000份儿,宏观上就变成了并发的多线程),那任务执行就得看运气了----线程的优先级可以影响操作系统的优先调度。
- 结束无序
正是因为多线程具有不确定性,很多时候想法不一定按照想法去执行,大部分是ok的,但是总有一定的概率出现问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!