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调用事件

调用事件的代码很简单,它的语法和调用一个方法类似,直接使用事件的名称,并传入事件的参数就可以了。
protected virtual void OnChanged(EventArgs e)
        {
            if (Changed != null)
            {
                Changed(this, e);
            }
        }
需要注意的是,在该方法中要判断是否有对象将委托与该事件关联,如果没有对象将委托与事件关联,则委托的事件为null。调用事件时先检查是否为null,如果不为null,再调用该事件。
谁来调用这个事件呢?由于本例子的目的是当ListWithChangedEvent的实例list的内容改变时触发事件,所以应该在ListWithChangedEvent的Add方法和Clear方法中调用这个事件。
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声明事件发生时处理的方法

对于接收事件的对象而言,需要编写一个方法,以便在感兴趣的事件出发时,能够执行这个方法内的代码。
下面的例子定义了一个方法ListChanged。需要注意的是,事件处理方法的参数类型和个数必须和delegate类型定义的一致,不过参数的名称可以相同也可以不同,例子中使用了相同的名称:
private void ListChanged(object sender, EventArgs e)
{Console.WriteLine("开始让我处理了!");
}

这个方法有什么用呢?开始说过,当邮局接收到杂志后,它要进行处理,比如将杂志送到订户指定的单位等。也就是说,这个方法就是告诉邮局如何处理的。

2.4将事件和委托关联在一起

邮局已经知道如何处理了,可还没有指明是哪个邮局作这个处理,还必须指明哪个邮局、如何处理。也就是说,需要将事件和委托关联在一起。

使用+=将事件和委托关联在一起,使用-=接触关联。一旦建立起这种关联,委托就可以调用事件发生时处理的方法。
例子中的事件Changed和委托ChangedEventHandler关联在一起,并指明当事件发生时,调用参数中指明的方法ListChanged。
List.Changed += new ChangedEventHandler(ListChanged);
这样,委托ChangedEventHandler就知道,当对象的状态改变(调用Add方法或者Chear方法)时,就调用Changed事件,调用CHanged事件时就执行ListChanged这个方法。
在.net开发环境中,当控件的状态改变时,比如用户单击了按钮控件,控件就会发出一个事件,编程者只需要声明触发事件时执行的方法就可以了。例子只是为了让读者理解事件的工作原理,以及进行复杂编程时自定义事件的方法。实际上,一般情况下利用.net提供的事件进行编程就已经足够了,而且使用也非常简单。但是有时还确实需要利用事件实现一些特殊功能。

C#基础-委托与事件相关推荐

  1. 面向对象基础-委托与事件

    首先举一个实例: 创建一个控制台程序,需求是:有一只猫Tom,有两只老鼠Jerry和Jack,Tom只叫一声"喵,我是Tom",两只老鼠就说"老猫来了,快跑", ...

  2. .NET基础示例系列之六:委托及事件

    委托是一个类. 定义委托时,实是定义一个用户自定义的类,它能代表具有相同参数列表和返回类型的任何方法,方法可以是静态方法或成员方法.示例: public partial class Form1 : F ...

  3. 【.NET基础】--委托、事件、线程(2)

    本文介绍event的使用以及原理,本文接上一篇文章的Demo继续[下载上一篇Demo] 上一篇我们在类(dg_SayHi.cs)里面定义代理了4个Delegate,然后在Button的后台事件中 新建 ...

  4. C#基础加强(8)之委托和事件

    委托 简介 委托是一种可以声明出指向方法的变量的数据类型. 声明委托的方式 格式: delegate <返回值类型> 委托类型名(参数) ,例如: delegate void MyDel( ...

  5. [C#]委托和事件(讲解的非常不错)

    引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...

  6. C#综合揭秘——深入分析委托与事件

    引言 本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C# 当中事件(Event)的由来,它能使处理委托类型的过程变得更加简单. 还将为您解释委托的协变与逆变,以及如何使用 Deleg ...

  7. C#语法:委托与事件

    在C#中,每一个事件都是依靠委托来完成的.本次写的是如何编写自定义事件.其实不难,按步骤来就行... using System; using System.Collections.Generic; u ...

  8. C#委托、事件、消息(入门级)

    本文的内容需要一定的OOP知识,不过我会在另一个内容介绍,由于实现细节,我会先写这部分. 大家关于委托.事件和消息大多是从WinForm编程接触的,首先是你在可视化的设计器里双击控件写所谓事件的处理代 ...

  9. C# 委托(Delegate) 事件(Event)应用详解

    委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每 ...

最新文章

  1. 技术是最求 买卖是境界
  2. 事件绑定及解除事件绑定
  3. .NET多线程编程(7)——C#多线程编程传递参数解决方案
  4. 标准正弦波变频电源调制方式的实现
  5. centos7 禁止ip访问_centos7.6版本限制某个IP访问指定端口
  6. c语言 链表_C语言编程第22讲——单向有序链表的C语言实现
  7. win32开发(图形绘制)
  8. linux 快速启动程序,centos7快速启动应用程序教程
  9. Fiddler 4 模拟 服务端返回 json
  10. 判断点在多边形内(射线法)
  11. OPENCV中定义ROI区域以及ROI区域的相关融合(程序解读)
  12. IT 项目的安全需求(一)— CLASP
  13. katacontainers v2编译
  14. 2020最新版python基础入门学习视频教程
  15. Linux: systemd 启动代码分析
  16. STM32 CAN总线故障检测功能的使用
  17. MATLAB对一子数组赋值
  18. wordpress实现全站HTTPS
  19. oracle基础语句练习
  20. 字软元件和位软元件的区别

热门文章

  1. 基于云计算的视频会议系统特点与价值
  2. 原生js实现文字转语音功能
  3. LOTO示波器 软件功能 井字测量光标的锁定功能用于跨屏幕测量
  4. 天正立面lisp什么意思_天正建筑如何画立面图和剖面图?一步一步教会你
  5. 网综同质化的这一年,为何“剧情式”会胜出?
  6. 项目-企业客户关系管理系统(登录+首页操作菜单)
  7. 奈何本人没文化,一句卧槽行天下
  8. 传播最广的一篇SVM算法博文
  9. Java 基本类型与自动装箱、拆箱
  10. vue组件-echarts地图显示柱状图并给柱状图添加点击事件(支持自定义地图)