C# 委托与事件介绍

ops/2025/2/12 17:07:12/

.NET学习资料

.NET学习资料

.NET学习资料


在 C# 编程中,委托(Delegate)与事件(Event)是两个重要且紧密相关的概念,它们为程序提供了强大的灵活性和可扩展性,尤其在实现代码之间的松散耦合和事件驱动编程方面发挥着关键作用。

一、委托

(一)定义

委托是一种引用类型,它定义了方法的签名,即方法的参数列表和返回类型。简单来说,委托可以看作是对方法的一种 “抽象引用”,允许将方法作为参数传递给其他方法,或者将方法赋值给变量 。这就好比在 C 或 C++ 中函数的指针,但委托是类型安全且完全面向对象的,克服了指针可能带来的安全隐患。例如,定义一个简单的委托类型:

public delegate void GreetingDelegate(string name);

上述代码定义了一个名为GreetingDelegate的委托,它指向的方法接受一个string类型的参数,并且没有返回值。

(二)特点

方法作为参数传递:委托最大的特点之一就是允许将方法当作另一个方法的参数进行传递,从而实现代码的动态行为。例如:

public void GreetPeople(string name, GreetingDelegate MakeGreeting)
{MakeGreeting(name);
}

在这个方法中,GreetPeople接受一个GreetingDelegate类型的参数MakeGreeting,在调用GreetPeople时,可以传入不同的方法,如EnglishGreeting或ChineseGreeting,动态决定具体的问候方式。

private static void EnglishGreeting(string name)
{Console.WriteLine("Morning, " + name);
}
private static void ChineseGreeting(string name)
{Console.WriteLine("早上好, " + name);
}
// 调用GreetPeople方法,传入不同的问候方法
GreetPeople("Jimmy Zhang", EnglishGreeting);
GreetPeople("张子阳", ChineseGreeting);

可用于定义回调方法:在异步编程或需要在特定操作完成后执行某些代码的场景中,委托可以用来定义回调方法。比如,在进行异步网络请求时,当请求完成后,可以通过委托指定一个回调方法来处理返回的数据。

可以链接多个方法:委托对象可以通过+和-运算符来添加或移除方法,从而实现将多个方法链接在一起。当委托被调用时,会依次调用链接的所有方法 。例如:

public delegate void NumberChanger(int n);
public class ClassC
{public static event NumberChanger changer;public static void Test(){changer(100);}
}
public class Class2
{public static void ClassA_Test(int i){Console.WriteLine("Class2:" + i);}
}
public class Class3
{public static void ClassA_Test(int i){Console.WriteLine("Class3:" + i);}
}
// 链接多个方法
ClassC.changer += Class2.ClassA_Test;
ClassC.changer += Class3.ClassA_Test;
ClassC.Test();

上述代码中,ClassC.changer委托对象链接了Class2.ClassA_Test和Class3.ClassA_Test两个方法,当调用ClassC.Test()触发changer委托时,这两个方法会依次被执行。

(三)使用步骤

定义委托类型:根据需要调用的方法签名,定义一个委托类型。委托类型的参数列表和返回类型必须与要调用的方法一致。

创建委托对象实例:创建委托对象的实例,使其指向要调用的方法。可以通过直接赋值的方式,将方法名赋给委托对象。

将委托对象作为参数传递:在需要调用方法的地方,将委托对象作为参数传递给其他方法,从而实现对目标方法的调用。

二、事件

(一)定义

事件是一种特殊的委托,它基于委托机制,为委托提供了一个发布 / 订阅机制 。简单来说,事件允许对象向外部订阅者通知特定事件的发生,订阅者可以响应这些事件。在 C# 中,使用event关键字来声明事件。例如:

public delegate void MyEventHandler(object sender, EventArgs e);
public class MyClass
{public event MyEventHandler MyEvent;// 触发事件的方法protected virtual void OnMyEvent(EventArgs e){MyEvent?.Invoke(this, e);}
}

上述代码中,首先定义了一个MyEventHandler委托,然后在MyClass类中声明了一个MyEvent事件,该事件的类型为MyEventHandler。OnMyEvent方法用于触发MyEvent事件,在触发事件时,会调用所有订阅了该事件的方法。

(二)特点

事件只能在声明它的类内部触发:这是事件与委托的一个重要区别。事件的触发通常是由类内部的某些操作引起的,例如属性值的改变、某个任务的完成等。外部类无法直接触发事件,只能通过订阅事件来响应事件的发生。

用于外部接口和通知机制:事件主要用于类向外部提供一种通知机制,当类内部发生特定事件时,通知外部订阅者。例如,在图形用户界面(GUI)编程中,按钮的点击事件、窗口的关闭事件等,都是通过事件来通知程序的其他部分进行相应的处理。

基于委托机制:事件本质上是基于委托实现的,它使用委托来管理订阅者列表,并在事件发生时向所有订阅者触发方法调用。

(三)使用步骤

在类中定义事件:使用event关键字在类中定义一个事件,事件的类型必须是已定义的委托类型。

订阅者订阅事件:外部订阅者通过+=运算符将方法添加到事件中,实现对事件的订阅。例如:

MyClass myObj = new MyClass();
myObj.MyEvent += new MyEventHandler(MyEventHandlerMethod);

上述代码中,MyEventHandlerMethod是订阅者定义的处理事件的方法,通过+=运算符将其添加到myObj.MyEvent事件中。

事件触发和处理:当类内部满足事件触发条件时,调用触发事件的方法,此时会自动调用所有订阅者的事件处理方法。在事件处理方法中,可以编写相应的逻辑来处理事件。例如:

// 触发事件
myObj.OnMyEvent(new EventArgs());

上述代码中,调用myObj.OnMyEvent方法触发MyEvent事件,从而调用MyEventHandlerMethod方法进行事件处理。

三、委托与事件的关系

委托是事件的底层机制,事件依赖于委托来实现其功能。事件使用委托来管理订阅者列表,当事件发生时,通过委托调用所有订阅者的方法 。可以说,事件是在委托基础上的一种更高级的抽象,它为委托提供了更安全、更方便的使用方式,主要用于实现对象之间的事件通知和交互。

在实际编程中,委托和事件经常一起使用。例如,在实现观察者模式时,被观察者可以通过事件来通知观察者状态的变化,而委托则用于定义事件的处理方法签名和实现事件的调用机制。通过委托和事件的结合使用,可以实现代码的高度解耦和可维护性,提高程序的灵活性和可扩展性。

总之,委托和事件是 C# 编程中非常重要的概念,理解和掌握它们的使用方法对于编写高质量、可维护的 C# 程序至关重要。无论是在桌面应用程序开发、Web 应用程序开发还是其他类型的软件开发中,委托和事件都有着广泛的应用场景。希望通过本文的介绍,能帮助你更好地理解和运用 C# 中的委托与事件。


http://www.ppmy.cn/ops/157124.html

相关文章

Java中List集合的面试试题及答案解析

Java集合类是Java编程中非常重要的一部分,主要用于存储和管理对象。以下是一些常见的Java集合类及其简要介绍: List接口 ArrayList:基于动态数组实现,支持随机访问元素,适合频繁的索引操作,但插入和删除元素…

MoviePy,利用Python自动剪辑tiktok视频

Python剪辑视频是非常强大的,而且能流水线批量操作,可以使用MoviePy库实现。 最近看到一个Github项目,作者利用Python写了一个自动生成tiktok视频的脚本,受到热捧。 现在像抖音、tiktok上有很多流水线生产的视频,不少…

如何打开vscode系统用户全局配置的settings.json

📌 settings.json 的作用 settings.json 是 Visual Studio Code(VS Code) 的用户配置文件,它存储了 编辑器的个性化设置,包括界面布局、代码格式化、扩展插件、快捷键等,是用户全局配置(影响所有…

apisix的real-ip插件使用说明

k8s集群入口一般都需要过负载均衡,然后再到apisix。 这时候如果后台业务需要获取客户端ip,可能拿到的是lb或者网关的内网ip。 这里一般要获取真实ip需要做几个处理。 1. 负载均衡上,一般支持配置获取真实ip参数,需要配置上。然…

第八届大数据与应用统计国际学术研讨会(ISBDAS 2025)

重要信息 官网:www.is-bdas.org 时间:2025年2月28-3月2日 地点:中国 广州 主办单位:广东省高等教育学会人工智能与高等教育研究分会 协办单位:北京师范大学人工智能与未来网络研究院、人工智能与大数据科研基地 …

微信小程序案例1——制作猫眼电影底部标签导航栏

文章目录 一、项目步骤1 新建一个无AppID的movie项目2将准备好的底部标签导航图标拷贝到movie项目下面(将图标文件夹image放到项目文件夹里)3 打开App.json配置文件,在pages数组里添加4个页面路径:电影“pages/movie/movie”、影院“pages/cinema/cinema…

USB枚举过程及Linux下U盘识别流程

USB枚举过程及Linux下U盘识别流程 USB枚举过程Linux 内核U盘识别流程打开内核动态输出时候的U盘插拔log内核工作队列检测HUB端口变化hub_event() 函数hub_port_connectUSB连接去抖枚举USB设备hub_port_initUSB接口与USB设备匹配USB接口驱动USB-STORAGE 接口驱动中USB 识别并添加…

【Python实战练习】Python类中的方法:形式与作用详解

文章目录 Python类中的方法:形式与作用详解1. 实例方法 (Instance Method)定义与使用作用2. 类方法 (Class Method)定义与使用作用3. 静态方法 (Static Method)定义与使用作用4. 特殊方法 (Magic/Dunder Methods)常见的特殊方法定义与使用作用5. 抽象方法 (Abstract Method)定…