C#基础-委托与事件
1、委托
委托(delegate)是一种数据结构,提供类似C++中函数指针的功能。不同的是,C++的函数指针只能够指向静态的方法,而委托除了可以指向静态的方法之外,还可以指向对象实例的方法。其实,最大的差别在于delegate是完全的面向对象且实用安全的类型。另外,delegate允许编程人员可以在执行时期传入方法的名称,动态地决定欲调用的方法。
委托的最大特点是,它不知道或不关心自己引用的对象的类。任何对象中的方法都可以通过委托动态地调用,只是方法的参数类型和返回类型必须与委托的参数类型和返回类型相匹配。这使得委托完全适合“匿名”调用。
委托主要用在两个方面:其一是CallBack(回掉)机制;其二是事件处理。
建立和使用delegate类型可按照下面的步骤进行,其后的例子给出了完整的程序代码。
1)声明样板。
首先要声明一个delegate类型:
public delegate string MyDelegate(string name);
代码中先定义一个delegate类型,名为MyDelegate,它包含一个string类型的传入参数name,一个string类型的返回值。当C#编译器编译这行代码时,会生成一个新的类,该类继承自System.Delegate类,而类的名称为MyDelegate。
从语法形式上看,定义一个委托非常类似于定义一个方法。即:
访问修饰符 delegate 类型 委托名(参数序列)
但是,方法有方法体,而委托没有方法体。因为它执行的方法是在使用委托时动态指定的。
2)定义准备调用的方法。
由于这个方法是通过delegate调用的,因此,此方法的参数类型、个数以及参数的顺序都必须和delegate类型相同。
下面的程序中定义了两个方法:FunctionA与FunctionB。这两个方法的参数和MyDelegate的类型一样,有一个string类型的传入参数,有一个string类型的返回值。
public static string FunctionA(string name){......}
public static string FunctionB(string name){......}
3)定义delegate类型的处理函数,并在此函数中通过delegate类型调用定义的方法。
在下面的例子中,处理函数的功能比较简单,仅仅输出一个字符串,字符串中包含通过MyDelegate类型调用的方法得到的输出内容。
public static void MethodA(MyDelegate Me)
{Console.WriteLine(Me("张三"));
}
由于MyDelegate类型的定义中有一个string类型的传入参数,所以使用时也必须传入一个字符串,即:Me("张三")。
因此,如果Me指向的FunctionA,则会执行FunctionA内的程序代码,如果Me指向的是FunctionB,则会执行FunctionB内的程序代码。
4)创建实例,传入准备调用的方法名。
由于声明了一个delegate类型在编译时期会被转换成一个继承自System.Delegate的类,因此要使用delegate类型时,必须先建立delegate的实例,并把它关联到一个方法。
MyDelegate a = new MyDelegate(FunctionA);
本行代码的含义是:a指向FunctionA方法的程序代码段。
建立delegate类型的实例后,就可以直接调用处理函数,并传入delegate类型的变量。
例如:
MethodA(a);
由于a指向FunctionA的引用,所以实际执行的FunctionA中的程序代码。
【例】使用delegate
using System;
namespace test
{
//第一步:声明委托
public delegate string MyDelegate(string name);
public class test
{
//第二步:定义被调用的方法
public static string FunctionA(string name)
{
return "A say Hello to " + name;
}
public static string FunctionB(string name)
{
return "B say hello to " + name;
}
//第三步:定义delegate类型的处理函数,并在此函数中通过delegate类型调用第二步定义的方法
public static void MethodA(MyDelegate Me)
{
Console.WriteLine(Me("张三"));
}
public static void Main()
{
//第四步:创建实例,传入准备调用的方法名
MyDelegate a = new MyDelegate(FunctionA);
MyDelegate b = new MyDelegate(FunctionB);
MethodA(a);
MethodA(b);
Console.ReadLine();
}
}
}
程序输出结果为:
A say Hello to 张三
B say Hello to 张三
2、事件
“事件”是指当对象发生某些事情时,向其他对象提供通知的一种方法。在C#中,事件是通过delegate实现的。
事件有两个角色:一个是事件发送方,一个是事件接收方。事件发送方是指触发事件的对象,事件接收方是指注册想在某种事件发生时被通知的对象。
举例说明,目前有很多期刊杂志,而你可以只订购感兴趣的杂志。一旦你订购了指定的杂志,当这些杂志发行时,就会将这些杂志送到你指定的地方(单位或者代办处)。此时发行杂志的出版社就称为事件发送方,你就是事件接收方。而每当杂志发行时,就触发一个发行事件。但出版社并不是直接将杂志送给你,而是委托邮局做这件事,或者说邮局是出版社的委托。
事件发送方其实就是一个对象,这个对象会自行维护本身的状态信息。当本身的状态信息变动时,便触发一个事件,并通知所有的事件接收方。
事件接收方可以注册感兴趣的事件。一般提供一个事件处理程序,以便在事件发送方触发一个事件后,会自动执行这段程序代码的内容。
事件最常见的用途是用于图形用户界面。一般情况下,每个控件都有一些事件,当用户对控件进行某些操作(如单击某个按钮)时,系统就会将相关信息告诉这些事件。
2.1声明一个事件
事件是通过delegate机制实现的,因此若要声明一个事件,首先要声明一个delegate类型,然后使用event保留字声明一个事件,并将事件名称和delegate类型关联在一起。
【例】事件处理
using System;
namespace MyCollections
{
using System.Collections;
public delegate void ChangeEventHandler(object sender,EventArgs e);
public class ListWithChangeEvent:ArrayList
{
public event ChangeEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
{
Changed(this, e);
}
}
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}
public override void Clear()
{
base.Clear();
OnChanged(EventArgs.Empty);
}
public override object this[int index]
{
set
{
base[index] = value;
OnChanged(EventArgs.Empty);
}
}
}
}
using System;
namespace TestEvents
{
using MyCollections;
class EventListener
{
private ListWithChangeEvent List;
public EventListener(ListWithChangeEvent list)
{
List = list;
List.Changed += new ChangeEventHandler(ListChanged);
}
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("开始让我处理了!");
}
public void Detach()
{
List.Changed -= new ChangeEventHandler(ListChanged);
List = null;
}
}
class Test
{
public static void Main()
{
ListWithChangeEvent list = new ListWithChangeEvent();
EventListener listener = new EventListener(list);
list.Add("item 1");
list.Clear();
listener.Detach();
Console.ReadKey();
}
}
}
输出结果为:
开始让我处理了!
开始让为处理了!
例子中声明了一个delegate类型,名称为ChangedEventHandler,并带有两个参数,这有点像先指定一个邮局,并告诉邮局出版社是谁(object sender),出版社都有哪些信息(EventArgs e)。
public delegate void ChangedEventHandler(object sender,EventArgs e);
然后声明一个事件,名称为Changed,并指明用ChangedEventHandler作为委托。
public event ChangedEventHandler Changed;
这样做的目的是,当触发Changed事件时,可以通过ChangedEventHandler这个委托进行事件处理。就好像订购杂志时先要指明和哪个邮局(出版社的委托)建立联系,以便邮局接到杂志时(触发事件时)可以将杂志送给你。此处的ChangedEventHandler相当于邮局,Changed相当于订购杂志者。
2.2调用事件
{
if (Changed != null)
{
Changed(this, e);
}
}
public class ListWithChangedEvent::ArrayList
{......public override int Add(object value){int i = base.Add(value);OnChanged(EventArgs.Empty);return i;}......
}
这样,当调用Add方法时,该方法就会调用OnChanged方法,而OnChanged方法中调用了Changed事件,所以也可以说当调用Add方法时调用了Change事件。
2.3声明事件发生时处理的方法
private void ListChanged(object sender, EventArgs e)
{Console.WriteLine("开始让我处理了!");
}
这个方法有什么用呢?开始说过,当邮局接收到杂志后,它要进行处理,比如将杂志送到订户指定的单位等。也就是说,这个方法就是告诉邮局如何处理的。
2.4将事件和委托关联在一起
邮局已经知道如何处理了,可还没有指明是哪个邮局作这个处理,还必须指明哪个邮局、如何处理。也就是说,需要将事件和委托关联在一起。
C#基础-委托与事件相关推荐
- 面向对象基础-委托与事件
首先举一个实例: 创建一个控制台程序,需求是:有一只猫Tom,有两只老鼠Jerry和Jack,Tom只叫一声"喵,我是Tom",两只老鼠就说"老猫来了,快跑", ...
- .NET基础示例系列之六:委托及事件
委托是一个类. 定义委托时,实是定义一个用户自定义的类,它能代表具有相同参数列表和返回类型的任何方法,方法可以是静态方法或成员方法.示例: public partial class Form1 : F ...
- 【.NET基础】--委托、事件、线程(2)
本文介绍event的使用以及原理,本文接上一篇文章的Demo继续[下载上一篇Demo] 上一篇我们在类(dg_SayHi.cs)里面定义代理了4个Delegate,然后在Button的后台事件中 新建 ...
- C#基础加强(8)之委托和事件
委托 简介 委托是一种可以声明出指向方法的变量的数据类型. 声明委托的方式 格式: delegate <返回值类型> 委托类型名(参数) ,例如: delegate void MyDel( ...
- [C#]委托和事件(讲解的非常不错)
引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...
- C#综合揭秘——深入分析委托与事件
引言 本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C# 当中事件(Event)的由来,它能使处理委托类型的过程变得更加简单. 还将为您解释委托的协变与逆变,以及如何使用 Deleg ...
- C#语法:委托与事件
在C#中,每一个事件都是依靠委托来完成的.本次写的是如何编写自定义事件.其实不难,按步骤来就行... using System; using System.Collections.Generic; u ...
- C#委托、事件、消息(入门级)
本文的内容需要一定的OOP知识,不过我会在另一个内容介绍,由于实现细节,我会先写这部分. 大家关于委托.事件和消息大多是从WinForm编程接触的,首先是你在可视化的设计器里双击控件写所谓事件的处理代 ...
- C# 委托(Delegate) 事件(Event)应用详解
委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每 ...
最新文章
- 技术是最求 买卖是境界
- 事件绑定及解除事件绑定
- .NET多线程编程(7)——C#多线程编程传递参数解决方案
- 标准正弦波变频电源调制方式的实现
- centos7 禁止ip访问_centos7.6版本限制某个IP访问指定端口
- c语言 链表_C语言编程第22讲——单向有序链表的C语言实现
- win32开发(图形绘制)
- linux 快速启动程序,centos7快速启动应用程序教程
- Fiddler 4 模拟 服务端返回 json
- 判断点在多边形内(射线法)
- OPENCV中定义ROI区域以及ROI区域的相关融合(程序解读)
- IT 项目的安全需求(一)— CLASP
- katacontainers v2编译
- 2020最新版python基础入门学习视频教程
- Linux: systemd 启动代码分析
- STM32 CAN总线故障检测功能的使用
- MATLAB对一子数组赋值
- wordpress实现全站HTTPS
- oracle基础语句练习
- 字软元件和位软元件的区别