原文发布时间为:2008-11-01 —— 来源于本人的百度文章 [由搬家工具导入]

.Net Framework中的委托与事件

尽管上面的范例很好地完成了我们想要完成的工作,但是我们不仅疑惑:为什么.Net Framework 中的事件模型和上面的不同?为什么有很多的EventArgs参数?

在回答上面的问题之前,我们先搞懂 .Net Framework的编码规范:

  1. 委托类型的名称都应该以EventHandler结束。
  2. 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
  3. 事件的命名为 委托去掉 EventHandler之后剩余的部分。
  4. 继承自EventArgs的类型应该以EventArgs结尾。

再做一下说明

  1. 委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
  2. EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。

上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热水器了。

现在我们改写之前的范例,让它符合 .Net Framework 的规范:

输出为:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Display:China Xian - RealFire 001:
Display:水快烧开了,当前温度:96度。
// 省略 ...

using System;
using System.Collections.Generic;
using System.Text;

namespace Delegate {
       // 热水器
       public class Heater {
              private int temperature;
              public string type = "RealFire 001";              // 添加型号作为演示
              public string area = "China Xian";                     // 添加产地作为演示
              //声明委托
              public delegate void BoiledEventHandler(Object sender, BoliedEventArgs e);
              public event BoiledEventHandler Boiled;       //声明事件

              // 定义BoliedEventArgs类,传递给Observer所感兴趣的信息
              public class BoliedEventArgs : EventArgs {
                     public readonly int temperature;
                     public BoliedEventArgs(int temperature) {
                            this.temperature = temperature;
                     }
              }

              // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
              protected virtual void OnBolied(BoliedEventArgs e) {
                     if (Boiled != null) {       // 如果有对象注册
                            Boiled(this, e);       // 调用所有注册对象的方法
                     }
              }
             
              // 烧水。
              public void BoilWater() {
                     for (int i = 0; i <= 100; i++) {
                            temperature = i;
                            if (temperature > 95) {
                                   //建立BoliedEventArgs 对象。
                                   BoliedEventArgs e = new BoliedEventArgs(temperature);
                                   OnBolied(e);       // 调用 OnBolied方法
                            }
                     }
              }
       }

       // 警报器
       public class Alarm {
              public void MakeAlert(Object sender, Heater.BoliedEventArgs e) {
                     Heater heater = (Heater)sender;              //这里是不是很熟悉呢?
                     //访问 sender 中的公共字段
                     Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
                     Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
                     Console.WriteLine();
              }

       }

       // 显示器
       public class Display {
              public static void ShowMsg(Object sender, Heater.BoliedEventArgs e) {       //静态方法
                     Heater heater = (Heater)sender;
                     Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
                     Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
                     Console.WriteLine();
              }
       }

       class Program {
              static void Main() {
                     Heater heater = new Heater();
                     Alarm alarm = new Alarm();

                     heater.Boiled += alarm.MakeAlert;       //注册方法
                     heater.Boiled += (new Alarm()).MakeAlert;              //给匿名对象注册方法
                     heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert);       //也可以这么注册
                     heater.Boiled += Display.ShowMsg;              //注册静态方法

                     heater.BoilWater();       //烧水,会自动调用注册过对象的方法
              }
       }
}

事件和委托: 第 6 页 .Net Framework中的委托与事件的更多相关文章

  1. Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

    一.多态 里氏替换原则: 任何能用基类的地方,可以用子类代替,反过来不行.子类能够在基类的基础上增加新的行为.面向对象设计的基本原则之一. 开放封闭原则: 对扩展开放,意味着有新的需求或变化时,可以对 ...

  2. 观察者模式与.Net Framework中的委托与事件

    本文文字内容均选自<大话设计模式>一书. 解释:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够 ...

  3. C# 中的委托和事件

    觉得这篇文章写的非常好,大神之作,由简入繁,对我这种初学者来说帮忙很大,特此留存下. 摘自:http://tracefact.net/CSharp-Programming/Delegates-and- ...

  4. C# 中的委托和事件(转)

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

  5. C# 中的委托和事件(转载)

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

  6. 【转】C# 中的委托和事件

    阅读目录 C# 中的委托和事件 引言 将方法作为方法的参数 将方法绑定到委托 事件的由来 事件和委托的编译代码 委托.事件与Observer设计模式 .Net Framework中的委托与事件 总结 ...

  7. c#中的委托和事件(转)

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

  8. C#中的委托、事件和设计模式(转载)

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

  9. 转载 -- C# 中的委托和事件

    原文地址:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx C# 中的委托和事件 引言 委 ...

随机推荐

  1. AJPFX总结java开发常用类(包装,数字处理集合等)(二)

    二:进军集合类 集合其实就是存放对象的容器,专业点说就是集合是用来存储和管理其他对象的对象,即对象的容器.集合可以扩容,长度可变,可以存储多种类型的数据,而数组长度不可变,只能存储单一类型的元素 用一 ...

  2. hdu4003/蓝桥杯 金属采集

    思路: 树形dp + 分组背包dp. 参考https://www.cnblogs.com/kuangbin/archive/2012/08/29/2661928.html 实现: #include & ...

  3. 洛谷P2763 试题库问题(最大流)

    题意 $n$道试题,每道题有多种类别属性 抽取$m$道题组成试卷,要求包含指定的类型 输出方案 Sol 又是一道zz网络流 我的构图长这样,$k_i$表示第$i$道试题需要的数量 #include&l ...

  4. iOS 自己手动添加编译警告

    文/青花瓷的平方(简书作者)原文链接:http://www.jianshu.com/p/b2e30cad2a0d著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 缘由 上一次生产环境我们 ...

  5. Eric's并发用户数估算与Little定律的等价性

    在国内性能测试的领域有一篇几乎被奉为大牛之作的经典文章,一个名叫Eric Man Wong 于2004年发表了名为<Method for Estimating the Number of Con ...

  6. whereis参数

    -b  只找二进制文件 -m 只找在帮助文件manual路径下的文件 -s 只找原文件 -u 没有帮助文件的文件 whereis passwd

  7. mac homebrew安装

    http://book.51cto.com/art/201107/278761.htm 3.2.3 使用 Homebrew 安装 Git Mac OS X 有好几个包管理器,用于管理一些开源软件在 M ...

  8. 2019年今日头条机试_JAVA后台岗_第一题

        广度优先遍历: import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; class Nod ...

  9. 指针-动态开点&合并线段树

    一个知识点不在一道题里说是没有灵魂的 线段树是用来处理区间信息的咯 但是往往因为需要4倍空间让许多人退却,而动态开点的线段树就非常棒 仿佛只用2倍就可以咯 指针保存位置,即节点信息,是很舒适的,所以用 ...

  10. Eaton Char-Lynn Motor : Performance Of Small Displacement Motors

    The small-displacement supercharged motor replaces the large-displacement motor with the speed of li ...