原文发布时间为: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. 网页尺寸scrollHeight/offsetHeight

    scrollHeight和scrollWidth,获取网页内容高度和宽度. 一.针对IE.Opera: scrollHeight 是网页内容实际高度,可以小于 clientHeight. 二.针对NS ...

  2. MSComDlg.CommonDialog服务器不能创建对象错误的解决

    作者:朱金灿 来源:http://blog.csdn.net/clever101 在JavaScript中弹出打开文件对话框,代码如下: var fileOpenDlg = new ActiveXOb ...

  3. JAVA设计模式--Strategy

    策略模式就是说当我进行比较大小的时候定义一个策略的比较器Comparator,然后由具体的比较策略来决定用什么量来比较大小.

  4. Can't locate ExtUtils/MakeMaker.pm in @INC

    Can't locate ExtUtils/MakeMaker.pm in @INC 解决办法:yum install perl-devel

  5. js中json处理总结之JSON.parse

    踩过的坑都将成为路上的风景.队友在cookie中已存以下值: address_info {"address_name":"人民大会堂","...lng ...

  6. 线程池ThreadPoolExecutor参数分析

    概述 比如去火车站买票, 有7个(maximumPoolSize)售票窗口, 但只有3个(corePoolSize)窗口对外开放.那么对外开放的3个窗口称为核心线程数, 而最大线程数是7个窗口. 如果 ...

  7. ZigBee cc2530芯片学习 error记录(1)

    ZigBee cc2530芯片学习 error记录   Error[e46]: Undefined external "LcdInit" referred in main( xxx ...

  8. Linux关闭命令行正在执行的程序

    Ctrl + C 终止    是强制中断程序的执行,,进程已经终止. Ctrl + Z   是将任务中止(暂停的意思),但是此任务并没有结束,他仍然在进程中他只是维持挂起的状态,用户可以使用fg/bg ...

  9. 浏览器title失去焦点时改变title

    document.addEventListener('visibilitychange', function() { var isHidden = document.hidden; if (isHid ...

  10. 【转】密码学 :CSP的概念

    转:[密码学]CSP的概念 CSP加密服务提供者(Cryptographic Service Provider)具有一下几个特点: CSP是真正执行密码运算的独立模块 物理上一个CSP由两部分组成:一 ...