首页 > 编程语言 >C#中委托和事件的区别

C#中委托和事件的区别

时间:2023-06-07 11:35:12浏览次数:40  
标签:DoSth sender 委托 区别 C# void object EventArgs

大致来说,委托是一个类,该类内部维护着一个字段,指向一个方法。事件可以被看作一个委托类型的变量,通过事件注册、取消多个委托或方法。本篇分别通过委托和事件执行多个方法,从中体会两者的区别。

 

□ 通过委托执行方法

class Program
{
static void Main(string[] args)
{
Example example = new Example();
example.Go();
Console.ReadKey();
}
}
public class Example
{
public delegate void DoSth(string str);
internal void Go()
{
//声明一个委托变量,并把已知方法作为其构造函数的参数
DoSth d = new DoSth(Print);
string str = "Hello,World";
//通过委托的静态方法Invoke触发委托
d.Invoke(str);
}
void Print(string str)
{
Console.WriteLine(str);
}
}

以上,

○ 在CLR运行时,委托DoSth实际上就一个类,该类有一个参数类型为方法的构造函数,并且提供了一个Invoke实例方法,用来触发委托的执行。
○ 委托DoSth定义了方法的参数和返回类型
○ 通过委托DoSth的构造函数,可以把符合定义的方法赋值给委托
○ 调用委托的实例方法Invoke执行了方法

 

但,实际上让委托执行方法还有另外一种方式,那就是:委托变量(参数列表)

public class Example
{
public delegate void DoSth(object sender, EventArgs e);
internal void Go()
{
//声明一个委托变量,并把已知方法作为其构造函数的参数
DoSth d = new DoSth(Print);
object sender = 10;
EventArgs e = new EventArgs();
d(sender, e);
}
void Print(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}

以上,

○ 委托DoSth的参数列表和方法Print的参数列表还是保持一致
○ 委托DoSth中的参数object sender通常用来表示动作的发起者,EventArgs e用来表示动作所带的参数。

而实际上,委托变量(参数列表),事件就是采用这种形式执行方法的。

 

□ 通过事件执行方法

public class Example
{
public delegate void DoSth(object sender, EventArgs e);
public event DoSth myDoSth;
internal void Go()
{
//声明一个委托变量,并把已知方法作为其构造函数的参数
DoSth d = new DoSth(Print);
object sender = 10;
EventArgs e = new EventArgs();
myDoSth += new DoSth(d);
myDoSth(sender, e);
}
void Print(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}

以上,

○ 声明了事件myDoSth,事件的类型是DoSth这个委托
○ 通过+=为事件注册委托
○ 通过DoSth委托的构造函数为事件注册委托实例
○ 采用委托变量(参数列表)这种形式,让事件执行方法

 

而且,通过+=还可以为事件注册多个委托。

public class Example
{
public delegate void DoSth(object sender, EventArgs e);
public event DoSth myDoSth;
internal void Go()
{
//声明一个委托变量,并把已知方法作为其构造函数的参数
DoSth d = new DoSth(Print);
DoSth d1 = new DoSth(Say);
object sender = 10;
EventArgs e = new EventArgs();
//为事件注册多个委托
myDoSth += new DoSth(d);
myDoSth += new DoSth(d1);
myDoSth(sender, e);
}
void Print(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
void Say(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}

 

以上,通过+=为事件注册1个或多个委托实例,实际上,还可以为事件直接注册方法。

public class Example
{
public delegate void DoSth(object sender, EventArgs e);
public event DoSth myDoSth;
internal void Go()
{
object sender = 10;
EventArgs e = new EventArgs();
//为事件注册多个委托
myDoSth += Print;
myDoSth += Say;
myDoSth(sender, e);
}
void Print(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
void Say(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}

 

□ 通过EventHandler执行方法

先来看EventHandler的源代码。

C#中委托和事件的区别_Go

可见,EventHandler就是委托。现在就使用EventHandler来执行多个方法。

public class Example
{
public event EventHandler myEvent;
internal void Go()
{
object sender = 10;
EventArgs e = new EventArgs();
//为事件注册多个委托
myEvent += Print;
myEvent += Say;
myEvent(sender, e);
}
void Print(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
void Say(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}

 

总结:
○ 委托就是一个类,也可以实例化,通过委托的构造函数来把方法赋值给委托实例
○ 触发委托有2种方式: 委托实例.Invoke(参数列表),委托实例(参数列表)
○ 事件可以看作是一个委托类型的变量
○ 通过+=为事件注册多个委托实例或多个方法
○ 通过-=为事件注销多个委托实例或多个方法
○ EventHandler就是一个委托



标签:DoSth,sender,委托,区别,C#,void,object,EventArgs
From: https://blog.51cto.com/u_4018548/6430500

相关文章

  • PCB板的Mark点设计对SMT重要性
    Mark点也称光学点、基准点,是电路板元器件组装中,PCBA应用于自动贴片机上的位置识别点。Mark点的选用,直接影响到自动贴片机的贴片效率,因此在设计时,需要设计好Mark点以及其在板内的位置。Mark点的设计1、布局位置单板Mark点在我们设计PCB时,贴片的一面需要添加Mark点,如果双面贴片则两面......
  • C++11中智能指针的原理、使用、实现
     目录理解智能指针的原理智能指针的使用智能指针的设计和实现1.智能指针的作用       C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,C++11中引入了智能指针的......
  • java.lang.OutOfMemoryError:GC overhead limit exceeded异常
    java.lang.OutOfMemoryError异常解决方法 原因:常见的有以下几种:1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;3.代码中存在死循环或循环产生过多重复的对象实体;4.使用的第三方软件中的BUG;5.启动参数内存......
  • 进阶篇丨链路追踪(Tracing)很简单:链路成本指南
    广义上的链路成本,既包含使用链路追踪产生的数据生成、采集、计算、存储、查询等额外资源开销,也包含链路系统接入、变更、维护、协作等人力运维成本。为了便于理解,本小节将聚焦在狭义上的链路追踪机器资源成本,人力成本将在下一小节(效率)进行介绍。链路追踪机器成本的组成结构链路追踪......
  • 关于c#:如何在不同的命名空间中处理相同的类名?
    Howtohandlesameclassnameindifferentnamespaces?我正在尝试创建一个通用的库结构。我通过为我想要的每个公共库创建单独的项目来做到这一点我有以下2个命名空间:MyCompany.ERP和MyCompany.Barcode我需要他们两个都有一个名为"Utilities"的类并且是静态的。如果这样做,我......
  • nginx 文件下载conf
    server{listen8088;server_namelocalhost;gzipon;gzip_staticon;#需要http_gzip_static_module模块gzip_min_length1k;gzip_comp_level4;gzip_proxiedany;gzip_typestext/plaintext/xmltext/css;gzip_varyon;gzip_dis......
  • 前端codeReview规范指南
    博主的写的:https://www.cnblogs.com/mrwh/p/17462559.html一、前言针对目录结构、CSS规范、JavaScript规范、Vue规范可参照官方给出的 风格指南:https://v2.cn.vuejs.org/v2/style-guide/index.html这里主要总结业务开发中常遇到的代码问题和实践,帮助大家后续各自做好codeReview,......
  • C++ 友元函数
    类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友......
  • redis-cli连接并管理redis集群
    某些场景下,redis集群以内网ip发现节点并提供服务,所以只能在服务器环境下以内网ip访问,此时redis-cli无疑是最可靠的工具。而各种gui工具都傻眼了(当然webui类工具除外)。redis-clinodejs版redis-clinodejs版可以脱离redis-server独立安装。安装yuminstallepel-releas......
  • STM32F429 Discovery开发板应用:实现SPI-SD Card文件写入(搭载FatFS文件系统)
    MCU:STM32F429ZIT6开发环境:STM32CubeMX+MDK5 外购了一个SPI接口的SDCard模块,想要实现SD卡存储数据的功能。首先需要打开STM32CubeMX工具。输入开发板MCU对应型号,找到开发板对应封装的MCU型号,双击打开(图中第三)。 此时,双击完后会关闭此界面,然后打开一个新界面。 ......