.NET委托,事件和Lambda表达式
委托
委托是什么?
委托是一种引用类型(其实就是一个类,继承MulticastDelegate特殊的类。),表示对具有特定参数列表和返回类型的方法的引用。
每个委托提供Invoke方法, BeginInvoke和EndInvoke异步方法
为什么需要委托?
- 委托可以将方法(即逻辑)作为参数;
- 逻辑解耦,保持稳定。
- 代码复用,保证项目规范。
如何使用委托?
如何声明、实例化和使用委托
声明委托
delegate void Del(string str);
static void Notify(string name)
{
Console.WriteLine($"Notification received for: {name}");
}
实例化委托
Del del1 = new Del(Notify);
//C# 2.0
Del del2 = Notify;
调用委托
del1.Invoke("小明");
del2("小明");
其他使用委托
//C# 2.0使用匿名方法来声明和实例化委托
Del del3 = delegate(string name)
{ Console.WriteLine($"Notification received for: {name}"); };
//C# 3.0使用lambda表达式声明和实例化委托
Del del4 = name => { Console.WriteLine($"Notification received for: {name}"); };
简化开发过程,.NET 包含一组委托类型:
- Action<> 具有参数且不返回值。
- Func<> 具有参数且返回由参数指定的类型的值。
- Predicate<> 用于确定参数是否满足委托条件的情况。
实际案例
代码:
class Program
{
/// <summary>
/// 声明委托
/// </summary>
/// <param name="fullName"></param>
private delegate void KillDelegate(string fullName);
static void Main(string[] args)
{
//实例化委托
var killWithKnifeDelegate = new KillDelegate(KillWithKnife);
Kill("郭靖", killWithKnifeDelegate);
var killWithSwordDelegate = new KillDelegate(KillWithSword);
Kill("黄蓉", killWithSwordDelegate);
var killWithAxeDelegate = new KillDelegate(KillWithAxe);
Kill("欧阳克", killWithAxeDelegate);
Console.ReadKey();
}
static void Kill(string fullName, KillDelegate killDelegate)
{
Console.WriteLine($"{fullName}遇到怪物");
//调用委托
killDelegate.Invoke(fullName);
Console.WriteLine($"{fullName}增长10经验");
}
static void KillWithKnife(string fullName)
{
Console.WriteLine($"{fullName}用刀杀怪物");
}
static void KillWithSword(string fullName)
{
Console.WriteLine($"{fullName}用剑杀怪物");
}
static void KillWithAxe(string fullName)
{
Console.WriteLine($"{fullName}用斧杀怪物");
}
}
Lambda表达式
Lambda是什么?
Lambda就是使用委托的更方便的语法。
//C# 2.0使用匿名方法来声明和实例化委托
Del del3 = delegate(string name)
{ Console.WriteLine($"Notification received for: {name}"); };
//C# 3.0使用lambda表达式声明和实例化委托
Del del4 = name => { Console.WriteLine($"Notification received for: {name}"); };
为什么需要Lambda?
简化开发过程,并不会影响运行性能。
如何使用Lambda?
表达式lambda基本形式:
//仅当 lambda 只有一个输入参数时,括号才是可选的;否则括号是必需的
(input-parameters) => expression
使用空括号指定零个输入参数:
Action line = () => Console.WriteLine();
括号内的两个或更多输入参数使用逗号加以分隔:
Func<int, int, bool> testForEquality = (x, y) => x == y;
语句lambda
(input-parameters) => { <sequence-of-statements> }
语句 lambda 的主体可以包含任意数量的语句;
Action<string> greet = name =>
{
string greeting = $"Hello {name}!";
Console.WriteLine(greeting);
};
greet("World");
// Output:
// Hello World!
使用匿名委托和lambda代码:
public static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 1; i <= 100; i++)
{
list.Add(i);
}
//使用匿名委托
List<int> result = list.FindAll(
delegate (int no)
{
return (no % 2 == 0);
}
);
foreach (var item in result)
{
Console.WriteLine(item);
}
//使用Lambda
List<int> result = list.FindAll(i => i % 2 == 0);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
事件
事件是什么?
事件是一种特殊的委托类型,主要用于消息或通知的传递。事件只能从事件的发布类型中调用,并且通常基于EventHandler委托,该委托具有代表事件发送者的对象和System.EventArgs派生的类,其中包含有关事件的数据。
何时使用委托和事件?
- 侦听事件是可选的:如果你的代码必须调用由订阅服务器提供的代码,则应使用基于委托的设计。如果你的代码在不调用任何订阅服务器的情况下可完成其所有工作,则应使用基于事件的设计。
- 返回值需要委托:用于事件的委托均具有无效的返回类型,事件处理程序通过修改事件参数对象的属性将信息传回到事件源。
- 事件具有专用调用:包含事件的类以外的类只能添加和删除事件侦听器;只有包含事件的类才能调用事件。
如何使用事件?
发布事件
定义事件数据
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
声明发布类中的事件
public delegate void CustomEventHandler(object sender, CustomEventArgs args);
public event CustomEventHandler RaiseCustomEvent;
//使用泛型版本
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
订阅事件
定义一个事件处理程序方法
void HandleCustomEvent(object sender, CustomEventArgs a)
{
// Do something useful here.
}
使用(+=) 添加订阅事件
publisher.RaiseCustomEvent += HandleCustomEvent;
使用(-=) 取消订阅事件
publisher.RaiseCustomEvent -= HandleCustomEvent;
示例
using System;
namespace DotNetEvents
{
// 定义事件信息的类
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
// 发布事件的类
class Publisher
{
// 使用EventHandler <T>声明事件
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
public void DoSomething()
{
RaiseCustomEvent(new CustomEventArgs("Event triggered"));
}
}
//订阅事件的类
class Subscriber
{
private readonly string _id;
public Subscriber(string id, Publisher pub)
{
_id = id;
// 添加订阅事件
pub.RaiseCustomEvent += HandleCustomEvent;
}
// 定义一个事件处理程序方法。
void HandleCustomEvent(object sender, CustomEventArgs e)
{
Console.WriteLine($"{_id} received this message: {e.Message}");
}
}
class Program
{
static void Main()
{
var pub = new Publisher();
var sub1 = new Subscriber("sub1", pub);
var sub2 = new Subscriber("sub2", pub);
// 调用引发事件的方法
pub.DoSomething();
Console.ReadKey();
}
}
}
参考
- 委托 https://docs.microsoft.com/zh-cn/dotnet/csharp/delegates-overview
- Lambda表达式 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/lambda-expressions
- 事件 https://docs.microsoft.com/zh-cn/dotnet/csharp/events-overview
.NET委托,事件和Lambda表达式的更多相关文章
- 委托,事件,lambda表达式
开篇说明三个点: 委托是一种类型 事件是委托的实例 lambda表达式是一个方法(匿名方法) [未完待续]
- C++实现委托机制(三)——lambda表达式封装
C++.引言: 其实原本没打算写这一章的,不过最后想了想,嗯还是把lambda表达式也一并封装进去,让这个委托也适应lambda表达式的注册.不过在之前还是需要先了解lamb ...
- 委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件【转】
1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委 ...
- (28)C#委托,匿名函数,lambda表达式,事件
一.委托 委托是一种用于封装命名和匿名方法的引用类型. 把方法当参数,传给另一个方法(这么说好理解,但实际上方法不能当参数,传入的是委托类型),委托是一种引用类型,委托里包含很多方法的引用 创建的方法 ...
- C#多线程+委托+匿名方法+Lambda表达式
线程 下面是百度写的: 定义英文:Thread每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它 ...
- 委托初级篇——lambda表达式的推导
public delegate void ConsoleWriteStr(string name,DateTime now); public delegate int DelegateAdd(int ...
- 委托、回调 Lambda表达式书写方式
- C#从委托、lambda表达式到linq总结
前言 本文总结学习C#必须知道的基础知识,委托.监视者模式.常用lambda表达式.linq查询,自定义扩展方法,他们之间有什么关系呢?匿名委托是如何演变成lambda表达式,lambda再如何导出l ...
- 委托的lambda表达式
委托可以用 Lambda 表达式的方法来表示,很多C#的代码都会大量使用 Lambda 表达式,正确理解它的用法还是很重要的. 基础规则: Lambda 运算符 “=>” 左边表示委托实例所需要 ...
随机推荐
- 性能分析(4)- iowait 使用率过高案例
性能分析小案例系列,可以通过下面链接查看哦 https://www.cnblogs.com/poloyy/category/1814570.html 前言 前面两个案例讲的都是上下文切换导致的 CPU ...
- C#设计模式之11-享元模式
享元模式(Flyweight Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/409 访问. 享元模式属 ...
- 四博智慧物联系统入门示例-1.增加一个DHT11温湿度传感器
1.准备工作 DOIT农业控制开发板或者esp32模组,并下载 四博智慧物联系统快速入门-2.准备工作 章节中的固件 DHT11连接在端口01 使用快速入门注册的管理账号和用户 2.配置网络 3.绑定 ...
- Vulnhub篇Photographerr
0x00 靶机信息 靶机:Photographerr:1 难度:中 下载:https://www.vulnhub.com/entry/photographer-1,519/ 0x01 信息收集 靶场网 ...
- 【NOI2015】荷马史诗 - 哈夫曼树
题目描述 追逐影子的人,自己就是影子 ——荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛&g ...
- 牛X!看完阿里P8架构师推荐的spring三剑客,成功涨薪5k
一直以来,Spring都被Java程序员视为杀手级别的应用,是为简化Java EE应用程序的开发为目标而创建的.Spring可以做很多事情,它为企业级开发提供给了丰富的功能,但是这些功能的底层都依赖于 ...
- neutron-server Connection pool is full, discarding connection 连接池过满
参考链接:https://zhiliao.h3c.com/Theme/details/48291 问题: -- ::33.235 WARNING requests.packages.urllib3.c ...
- Exploring Adversarial Attack in Spiking Neural Networks with Spike-Compatible Gradient
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:2001.01587v1 [cs.NE] 1 Jan 2020 Abstract 脉冲神经网络(SNN)被广泛应用于神经形态设 ...
- 牛客网PAT练兵场-在霍格沃茨找零钱
题目地址:https://www.nowcoder.com/pat/6/problem/4063 题意:按照题目的进制计算即可 /** * *作者:Ycute *时间:2019-11-14-21.45 ...
- 使用Seq搭建免费的日志服务
Seq简介 Seq是老外开发的一个针对.NET平台非常友好的日志服务.支持容器部署,提供一个单用户免费的开发版本. 官网:https://datalust.co/seq 使用文档:https://do ...