委托和事件:

1. 委托:一个能够表示方法的数据类型;它将方法作为对象封装起来,允许在运行时间接地绑定一个方法调用。

2. 声明委托数据类型:

public delegate  bool GreaterThanHandler(int first , int second);

3. 委托的实例化:

为了实例化委托,需要和委托类型自身的签名对应的一个方法;实例时不必用new来实例化该类的实例,直接传递名称即可[C#2.0新语法]。 如:

GreaterThanHandler a = 方法名;

C#2.0以前的语法:

GreaterThanHandler a = new GreaterThanHandler (方法名) ;

4. 匿名方法:

匿名方法没有实际方法声明的委托实例,它们的定义是直接内嵌在代码中的。如:

GreaterThanHandler a = delegate(int first , int second){return (first<second);};

5. 委托的内部机制:

C#将所有委托定义成间接派生于System.Delegate ,这个类有两个属性:(1)MethodInfo(System.Reflection.MethodInfo类型): 定义了一个特定方法签名(包括方法的名称、参数和返回类型) (2)Target(Object类型):对象实例,其中包含了要调用的方法。

6. multicast委托:

一个委托变量可以引用一系列委托,在这一系列委托中,每个委托都顺序指向一个后续的委托,从而形成一个委托链, 或者称为multicast委托。

Publish-subscribe(发布-订阅)模式: 它对应这样一种情形:需要将单一的事件通知(比如对象状态发生的一个变化)广播给多个订阅者(subscriber).

7. 使用委托来编写Observer模式(publish-subscribe模式):

例: 一个加热器(Heater)和一个冷却器(Cooler)连接到同一个温度计(thermostat) 上。为了控制加热器和冷却器的打开和关闭,要向它们通知温度的变化,温度计将温度的变化发布(publish)给多个订阅者-也就是加热器和冷却器。

看一段代码:〔注意①②③④个步骤:〕

using System;

namespace test

{

//定义订阅者

class Cooler //冷却器

{

private float _Temperature;       //启动设备所需的温度

public float Temperature          //属性

{

get { return _Temperature; }

set { _Temperature = value; }

}

public Cooler(float temperature) //构造器

{

Temperature = temperature;

}

//③在事件订阅者中定义事件处理程序

public void OnTemperatureChanged(float newTemperature)    //订阅者方法

{

if (newTemperature > Temperature)

{

Console.WriteLine("Cooler:On");

}

else

{

Console.WriteLine("Cooler:Off");

}

}

}

class Heater //加热器

{

private float _Temperature;       //启动设备所需的温度

public float Temperature          //属性

{

get { return _Temperature; }

set { _Temperature = value; }

}

public Heater(float temperature) //构造器

{

Temperature = temperature;

}

//③在事件订阅者中定义事件处理程序

public void OnTemperatureChanged(float newTemperature)      //订阅者方法

{

if (newTemperature < Temperature)

{

Console.WriteLine("Heater:On");

}

else

{

Console.WriteLine("Heater:Off");

}

}

}

//定义发布者

class Thermostat

{

public delegate void TemperatureChangeHandler(float newTemperature);   //定义委托数据类型,注意这是一个嵌套类;

//①在事件发行者中定义一个事件

private TemperatureChangeHandler _OnTemperatureChange;   //存储订阅者列表,只需一个委托字段即可存储所有订阅者(委托链)。

public TemperatureChangeHandler OnTemperatureChange

{

get { return _OnTemperatureChange; }

set { _OnTemperatureChange = value;}

}

//设置由温度计报告的当前温度值并触发事件

private float _CurrentTemperature;

public float CurrentTemperature

{

get { return _CurrentTemperature; }

set

{

if (value != CurrentTemperature)

{

_CurrentTemperature = value;

//②在事件发行者中触发事件

TemperatureChangeHandler localOnChange = OnTemperatureChange;

if (localOnChange != null)    //调用一个委托之前,要检查它的值是不是空值。

{

localOnChange(value);  //触发事件

}

}

}

}

}

//连接发布者和订阅者

class Program

{

static void Main(string[] args)

{

Thermostat thermostat = new Thermostat();

Heater heater = new Heater(60);

Cooler cooler = new Cooler(80);

string temperature;

//④向事件发行者订阅一个事件

thermostat.OnTemperatureChange += heater.OnTemperatureChanged;   //向OnTemperatureChange注册订阅者;

thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;

Console.WriteLine("输入温度:");

temperature = Console.ReadLine();

thermostat.CurrentTemperature = int.Parse(temperature);

Console.ReadLine();

}

}

}

8. 委托运算符:

+= , -= ; + , - ;

注:使用赋值运算符,会清除之前的所有订阅者,并允许使用新的订阅者替换它们。

9. multicast委托的内部机制:

->delegate关键字是派生自System.MulticastDelegate的一个类型的别名;MulticastDelegate类包含一个对象引用和一个方法指针。当向一个multicast委托添加一个方法时,MulticastDelegate类会创建委托类型的一个新实例,在新实例中为新增的方法存储对象引用和方法指针,并在委托实例列表中添加新的委托实例作为下一项。MulticastDelegate类维护着由多个Delegate对象构成的一个链表。

但是有两个问题需要解决:

1)      错误处理:假如一个订阅者引发了一个异常,链中的后续订阅者就接收不到通知;

2)      方法返回值和传引用:因为调用一个委托,就有可能造成将一个通知发送给多个订阅者,假如订阅者会返回值,就不确定到底该使用哪个订阅者的返回值。

以上两个问题都可以用GetInvocationList()方法遍历每个委托调用列表来处理。

10. 事件:

事件的目的:

1)      event关键字的目的就是提供额外的封装,避免你不小心地以取消其他订阅者;

2)      事件确保只有包容类才能触发一个事件通知;

总言之:event关键字提供了必要的封装来防止任何外部类发布一个事件或取消之前的订阅者。

下面这段代码对上述代码进行了修改:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace test

{

//定义订阅者

class Cooler //冷却器

{

private float _Temperature;       //启动设备所需的温度

public float Temperature          //属性

{

get { return _Temperature; }

set { _Temperature = value; }

}

public Cooler(float temperature) //构造器

{

Temperature = temperature;

}

//③在事件订阅者中定义事件处理程序

public void OnTemperatureChanged(object sender, Thermostat.TemperatureArgs newTemperature)    //订阅者方法

{

if (newTemperature.NewTemperature > Temperature)

{

Console.WriteLine("Cooler:On");

}

else

{

Console.WriteLine("Cooler:Off");

}

}

}

class Heater //加热器

{

private float _Temperature;       //启动设备所需的温度

public float Temperature          //属性

{

get { return _Temperature; }

set { _Temperature = value; }

}

public Heater(float temperature) //构造器

{

Temperature = temperature;

}

//③在事件订阅者中定义事件处理程序

public void OnTemperatureChanged(object sender,Thermostat .TemperatureArgs newTemperature)      //订阅者方法

{

if (newTemperature.NewTemperature < Temperature)

{

Console.WriteLine("Heater:On");

}

else

{

Console.WriteLine("Heater:Off");

}

}

}

//定义发布者

class Thermostat

{

public class TemperatureArgs : System.EventArgs

{

public TemperatureArgs(float newTemperature)

{

NewTemperature = newTemperature;

}

public float NewTemperature

{

get { return _newTemperature; }

set { _newTemperature = value; }

}

private float _newTemperature;

}

//①在事件发行者中定义一个事件

public delegate void TemperatureChangeHandler(object sender, TemperatureArgs newTemperature);   //定义委托数据类型,注意这是一个嵌套类;

public event TemperatureChangeHandler OnTemperatureChange;

//public TemperatureChangeHandler OnTemperatureChange         //存储订阅者列表,只需一个委托字段即可存储所有订阅者(委托链)。

//{

//    get { return _OnTemperatureChange; }

//    set { _OnTemperatureChange = value; }

//}

//private TemperatureChangeHandler _OnTemperatureChange;

//设置由温度计报告的当前温度值并触发事件

public float CurrentTemperature

{

get { return _CurrentTemperature; }

set

{

if (value != CurrentTemperature)

{

_CurrentTemperature = value;

//②在事件发行者中触发事件

if (OnTemperatureChange != null)

{

OnTemperatureChange(this, new TemperatureArgs(value));

}

}

}

}

private float _CurrentTemperature;

}

//连接发布者和订阅者

class Program

{

static void Main(string[] args)

{

Thermostat thermostat = new Thermostat();

Heater heater = new Heater(60);

Cooler cooler = new Cooler(80);

string temperature;

//④向事件发行者订阅一个事件

thermostat.OnTemperatureChange += heater.OnTemperatureChanged;   //向OnTemperatureChange注册订阅者;

thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;

Console.WriteLine("输入温度:");

temperature = Console.ReadLine();

thermostat.CurrentTemperature = int.Parse(temperature);

//thermostat.OnTemperatureChange(44);

Console.ReadLine();

}

}

}

转载于:https://www.cnblogs.com/0515offer/p/4191918.html

委托和事件[delegate and event]_C#相关推荐

  1. C#编程利器之四:委托与事件(Delegate and event) (上)

    本文试图在.net Framework环境下,使用C#语言来描述委托.事件的概貌.希望本文能有助于大家理解委托.事件的概念,理解委托.事件的用途,理解它的C#实现方法,理解委托与事件为我们带来的好处. ...

  2. C#中委托与事件的使用-以Winform中跨窗体传值为例

    场景 委托(Delegate) 委托是对存有某个方法的引用的一种引用类型变量. 委托特别用于实现事件和回调方法. 声明委托 public delegate int MyDelegate (string ...

  3. C# delegate与event,委托与事件

    文章目录 委托 示例 事件 实例 博主写作不容易,孩子需要您鼓励 万水千山总是情 , 先点个赞行不行 委托和事件是C#中两个比较复杂的概念,这篇文章介绍两个概念与基本用法,让大家理解C#中的事件处理机 ...

  4. 七天学习计划_c#_[2][3][4][5]委托、事件、委托与事件的区别、泛型委托、Func\Action\predicate

    由于委托之前的博客已经详细写了,这里就简单的过一遍,复习一下: 了解委托 基于委托开发事件驱动程序变得非常简单. 使用委托可以大大简化多线程编程难度. 理解委托 委托也可以看做成一种数据类型,可以定义 ...

  5. c#url拼接方法名_C# 从1到Core委托与事件

    委托与事件在C#1.0的时候就有了,随着C#版本的不断更新,有些写法和功能也在不断改变.本文温故一下这些改变,以及在NET Core中关于事件的一点改变. 一.C#1.0 从委托开始 1. 基本方式 ...

  6. c# 创建委托 消息订阅_C#面向对象之委托和事件

    委托 1.定义:委托也叫代理,就是把事情交给别人来做. 2.声明委托语法: delegate 返回类型 委托名称(); 委托使用步骤 1.声明委托 public delegate int Calcul ...

  7. C# 委托与事件(delegate)

    一说到 委托 总有那些 经典的现实例子,找个人 代替自己去做某事. 今天老师布置了一大堆作业,小明回家做作业,这可以理解成一个事件,但是小明不会做于是委托朋友 小鹏 帮忙做 哈哈.这就是对委托的字面上 ...

  8. c#事件的发布-订阅模型_C# 委托和事件 与 观察者模式(发布-订阅模式)讲解 by天命...

    使用面向对象的思想 用c#控制台代码模拟猫抓老鼠 我们先来分析一下猫抓老鼠的过程 1.猫叫了 2.所有老鼠听到叫声,知道是哪只猫来了 3.老鼠们逃跑,边逃边喊:"xx猫来了,快跑啊!我是老鼠 ...

  9. C# 委托、事件、回调 讲解

    一.C# 委托.事件.回调 基础概念 1.委托是C#中实现事件.回调的基础 2.委托的概念:Delegate C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针. 委托(Deleg ...

最新文章

  1. 7.1.1 [Enterprise Library]缓存应用程序块场景和目标
  2. 人工智能与区块链交换了眼神儿,之后呢……
  3. python3调用腾讯AI开放平台
  4. 如何获取文件的完整路径?
  5. python学习笔记(三)—— 序列类型及方法(列表、元组、字符串)
  6. 计算机数据恢复专业,专业电脑数据恢复软件哪个好
  7. 使用grep4j轻松测试分布式组件上的SLA
  8. 252.Meeting Rooms
  9. 快速上手 flask
  10. ActiveMQ学习(四)——应用程序接口
  11. JS中的事件委托/事件代理详解
  12. VS Newtonsoft的引用问题
  13. tomcat设置JAVA_OPTS
  14. 日期组装 (如:2020年1月1日、二〇二〇年一月一日、1/1/2020)
  15. 使用Vue制作幻灯片
  16. 网易2017春招笔试——工作安排
  17. C语言控制台程序添加图标(基于GCC编译器)
  18. 史上最全Lambda 钱包使用教程
  19. C语言(二)BMP图像 文本数据保存为图像
  20. 被李刚儿子撞死的漂亮姑娘——晓风(照片)

热门文章

  1. 腾讯IM可以实现聊天信息保存到本地服务器吗
  2. JTS(Geometry)工具类
  3. mysql查看所有触发器以及存储过程等操作集合
  4. pip 错误:ModuleNotFoundError: No module named pip
  5. Go学习笔记一:基础知识
  6. 修改linux终端的提示字符
  7. 第14天:逻辑运算符、if、for语句
  8. nodeJS之二进制buffer对象
  9. JS实现表单多文件上传样式美化支持选中文件后删除相关项
  10. Spring 整合Quartz 2实现定时任务五:集群、分布式架构实现探讨