记得我在初学.NET的时候对委托和事件这对概念理解的是很模糊的,当时在看书的时候只能理解书中代码的逻辑,知道委托和事件怎样用代码具体实现,但对其中的原理理解甚少。这几天在学习ASP.NET网页编程的时候,里面又多次提到了事件、事件参数。于是我决定再重新理解一次委托和事件

为了形象的描述委托和事件实现的过程,我想到了“喜羊羊和灰太狼”的故事。我比较爱看动画片,尤其是爱看像《喜羊羊与灰太狼》、《蜡笔小新》等这样既搞笑又弱智的动画片。没看过《喜羊羊与灰太狼》的可以趁此机会看一下。
为了描述这个故事,我们首先需要建立两个类:Goat和Wolf
//狼类的代码
public class Wolf{string name;    //定义一个变量用于存储狼的姓名//构造函数public Wolf(string name){this.name = name;}public string Name{get { return name; }set { name = value; }}public void Scare()    //狼有一个恐吓的方法{Console.WriteLine("哈哈,我是{0},小肥羊们快跟我回狼堡吧!",name );Console.WriteLine(); }}
//山羊类的代码
public class Goat{string name;    //定义一个变量用于存储山羊的名字//构造函数public Goat(string name){this.name = name;}public string Name{get { return name; }set { name = value; }}public void Run()    //羊有一个逃跑的方法{Console.WriteLine("狼来啦,{0}快跑!" ,name); Console.WriteLine();}}
在动画片里,灰太狼每次看到小羊的时候都是先和小羊聊天、说一些吓唬小羊的话,然后再上去抓羊,这时候喜羊羊早就想出逃脱的办法了,怪不得每次灰太狼都抓不到羊,看到羊先和他们扯淡,然后才行动。
不说废话了,下面我给大家讲怎样用委托和事件实现:狼吓唬小羊,小羊听到后撒腿就跑。
首先我们要明白一个常识:灰太狼再笨也不会自己告诉小羊说我来了,你们快跑吧。所以在Wolf类当中不可以出现Goat类的对象,也就是说不可以把小羊的Run方法写在狼的Scare方法中。Wolf和Goat双方不能关联,那就要通过委托来解决这个问题
委托其实就是对方法的引用,一旦为委托分配了方法,那么委托就可以像方法一样使用。委托定义了对方法特征的抽象,委托和函数一样可以有参数和返回值,为委托分配的方法的格式要和委托一致,即方法的参数和返回值要和委托一样。委托可以看做是函数的“类”,为委托分配的函数就是委托的实例。
首先我们定义一个委托
public delegate void WolfScareEventHandler();    
定义一个没有参数和返回值的委托,委托的名字是WolfScareEventHandler,委托用关键字delegate声明,可以放在Wolf类的里面,也可以放在类外面,因为委托本身也是一种“特殊的类”
然后我们定义一个WolfScareEventHandler委托类型的事件WolfScare
public event WolfScareEventHandler WolfScare;
事件用Event关键字声明,事件要声明在Wolf类的内部,因为这个事件是属于Wolf类的(我们通常说类有三要素:属性、事件、方法)
包含WolfScare事件的Wolf类代码
public class Wolf{string name;//构造函数public Wolf(string name){this.name = name;}public string Name{get { return name; }set { name = value; }}//声明一个WolfScareEventHandler委托类型的事件public event WolfScareEventHandler WolfScare;public void Scare(){Console.WriteLine("哈哈,我是{0},小肥羊们快跟我回狼堡吧!",name );//下面是触发WolfScare事件的代码if (WolfScare != null){WolfScare();}}}
这样Wolf类就具有了事件,而且在狼执行Scare方法时事件会被触发,如果为事件分配了方法,那么将执行方法。
最关键的是要看主程序的代码:
static void Main(string[] args){Wolf bigWolf = new Wolf("灰太狼");        //声明一个Wolf类的对象bigWolf,名字是“灰太狼”//声明三个Goat对象Goat happyGoat = new Goat("喜羊羊");Goat lazyGoat = new Goat("懒羊羊");Goat strongGoat = new Goat("沸羊羊");//给事件分配方法bigWolf.WolfScare += new WolfScareEventHandler(happyGoat .Run );bigWolf.WolfScare += new WolfScareEventHandler(lazyGoat.Run);bigWolf.WolfScare += new WolfScareEventHandler(strongGoat.Run);bigWolf.Scare ();}
在主程序当中,为bigWolf对象的事件WolfScare分配了三个方法:happyGoat .Run、lazyGoat.Run、strongGoat.Run。用委托的好处就在这里,不用在Wolf类当中出现Goat类,而是在主程序当中为事件动态分配方法,而且这些方法可以是不同对象的方法,只要格式和委托类型一致就可以了。
这样在bigWolf执行Scare方法时,事件WolfScare会被触发,同时执行happyGoat .Run、lazyGoat.Run、strongGoat.Run三个方法,运行结果如下

有人会说.NET中控件事件过程一般都是带参数的,像下面这样:
protected void Button1_Click(object sender, EventArgs e){}
这个事件过程带两个参数sender和e,分别是object类型和EventArgs类型的。sender是指此事件是在哪个对象中被触发的,在这里就是Button1;e是一个事件参数,里面携带着一些与此事件相关的数据
那么我们对“喜羊羊和灰太狼”的代码进行改造,让它的事件也带参数
先定义一个事件参数类WolfScareEventArgs,让它继承EventArgs类
public class WolfScareEventArgs{string name;        //定义一个name变量,让它存储狼的名字,这样事件参数就可以携带狼的名字了public string Name{get { return name; }set { name = value; }}}
对委托改造:事件过程(即为委托分配的方法)是带参数的,那么委托也要带参数
public delegate void WolfScareEventHandler(object sender,WolfScareEventArgs e);
改造后的Wolf类
public class Wolf{string name;//构造函数public Wolf(string name){this.name = name;}public string Name{get { return name; }set { name = value; }}//声明一个WolfScareEventHandler委托类型的事件public event WolfScareEventHandler WolfScare;public void Scare(){Console.WriteLine("哈哈,我是{0},小肥羊们快跟我回狼堡吧!",name );Console.WriteLine();//下面是触发WolfScare事件的代码if (WolfScare != null){//定义一个事件参数对象WolfScareEventArgs args = new WolfScareEventArgs();args.Name = this.name;        //将狼的名字赋给事件参数的Name属性WolfScare(this,args );}//重写ToString方法,这样sender.tostring()就可以显示狼的名字了public override string ToString(){return this .name ;}}

Goat类的代码也要进行改造:
public class Goat{string name;//构造函数public Goat(string name){this.name = name;}public string Name{get { return name; }set { name = value; }}public void Run(object sender,WolfScareEventArgs e){Console.WriteLine("{0}来啦,{1}快跑!",e.Name ,name);     //在这里可以用参数e的Name属性显示出哪只狼来了Console.WriteLine("追我的狼是:"+sender.ToString ());     //这里可以用sender对象的ToString方法显示出触发事件的狼的名字Console.WriteLine();}}
主程序基本不用变,为了方便演示,我们把狼的名字改为“红太狼”
static void Main(string[] args){Wolf bigWolf = new Wolf("红太狼");Goat happyGoat = new Goat("喜羊羊");Goat lazyGoat = new Goat("懒羊羊");Goat strongGoat = new Goat("沸羊羊");//给事件添加方法bigWolf.WolfScare += new WolfScareEventHandler(happyGoat .Run );bigWolf.WolfScare += new WolfScareEventHandler(lazyGoat.Run);bigWolf.WolfScare += new WolfScareEventHandler(strongGoat.Run);bigWolf.Scare ();}
程序运行的效果:

讲到这里可能有很多人还是觉得上面讲的事件和.NET中的控件事件不太一样,其实他们的原理是一样的:
当我们双击某个控件时,代码编辑器会自动为我们编写好一个事件处理过程

protected void Button1_Click(object sender, EventArgs e){}
其实这里的Button1_Click 就类似于上面讲到的Goat类的Run方法。Button1_Click过程的背后是事件Button1.Click,它类似于上面的bigWolf.WolfScare事件。
其实Button1_Click可以是随便的一个名字,比如fun(object sender, EventArgs e),只要你在代码中添加如下语句:
Button1.Click+=New EventHandler(fun);
这样当Button1的Click事件被触发时,就会执行fun方法。你可以为Button1.Click事件分配任意多的方法,当事件被触发时,这些方法都会被执行。
你看到的事件过程都是类似于protected void Button1_Click(object sender, EventArgs e)这样的,这是因为:当你双击某个控件时,系统自动创建过程protected void Button1_Click(object sender, EventArgs e),并将它分配给事件Button1.Click. 你也可以把其它控件的事件过程分配给事件Button1.Click,如:
protected void TextBox1_TextChanged(object sender, EventArgs e){Response.Write("这是文本框的事件过程");}
Button1.Click+=New EventHandler(TextBox1_TextChanged)
这样单击Button1,TextBox1_TextChanged事件过程也会被执行。
总之事件过程和一般的函数和方法是一样的,只不过系统把它分配给了事件,当事件触发时,执行被分配的事件过程
事件的原理你明白了吗?

喜羊羊与灰太狼之委托与事件相关推荐

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

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

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

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

  3. 大白话系列之C#委托与事件讲解(一)

    从序言中,大家应该对委托和事件的重要性有点了解了吧,虽然说我们现在还是能模糊,但是从我的大白话系列中,我会把这些概念说的通俗易懂的.首先,我们还是先说说委托吧,从字面上理解,只要是中国人应该都知道这个 ...

  4. 委托、事件、事件访问器

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 委托与事 ...

  5. js中的事件委托或是事件代理详解(转载)

    起因: 1.这是前端面试的经典题型,要去找工作的小伙伴看看还是有帮助的: 2.其实我一直都没弄明白,写这个一是为了备忘,二是给其他的知其然不知其所以然的小伙伴们以参考: 概述: 那什么叫事件委托呢?它 ...

  6. JS事件委托或者事件代理原理以及实现

    事件委托(事件代理)原理:简单的说就是将事件交由别人来执行,就是将子元素的事件通过冒泡的形式交由父元素来执行. 为什么要用时间委托? 在JavaScript中,添加到页面上的事件处理程序数量将直接关系 ...

  7. 对C#下函数,委托,事件的一点理解!

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 今天一来是有点 ...

  8. 13委托和事件在观察者模式中的应用

    当一个被监视对象的方法执行会触发观察者Observer的方法的时候,我们就可以在被监视对象中声明委托和事件. 例子 有一个宠物追踪器挂宠物身上,只要宠物离开主人100米之外,主人手上的显示器显示警告信 ...

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

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

最新文章

  1. 【安全漏洞】CVE-2021-1732 win32k漏洞分析
  2. Django 学习(一)Django安装以及初步使用
  3. qt linux实现鼠标位置自动移动,【已解决】qt中鼠标能显示但是无法移动
  4. 腾讯云加入自媒体分享计划可以免费领取.cn域名啦
  5. 在单独的WAR组件中对SPA资源和API实现进行分区
  6. 无心剑中译叶芝《情愁》
  7. 多个高危 BIOS 缺陷影响英特尔处理器,特斯拉 Model 3 未幸免,可用于供应链攻击...
  8. 完全卸载oracle11g
  9. matlab 最小二乘法拟合_最小二乘法辨识1阶离散传递函数
  10. eclipse 每次打开 提示 subversive svn connectors
  11. s7200cpu224xp手册_西门子plc s7-200系列|s7-200 cpu224xp|CPU224 XP 高速I/O
  12. Python处理Excel数据-pandas篇
  13. Intellig idea关闭自动更新
  14. mongodb for mac安装
  15. 高绩效团队-VUCA时代的五个管理策略《二》—代际管理
  16. jee6 学习笔记 5 - Struggling with JSF2 binding GET params
  17. 幸运数的定义及其判断
  18. Dubbo-Zookeeper注册中心;监控中心
  19. python爬取微博评论点赞数_python 爬虫 爬微博 分析 数据
  20. DR和DIS的区别?

热门文章

  1. MySQL语句中过滤条件放在哪?on、where还是having,他们区别和联系
  2. 将搜狗浏览器收藏夹导入到IE、Firefox、Chrome
  3. 利用 千千静听服务器 下载歌词 编写完毕 测试成功
  4. java profiles_使用Profiles
  5. PCB棕化处理-BondFilm
  6. 探索自然语言处理:理解、分析和生成人类语言
  7. 【生信学习第一天】DEseq2 差异表达基因计算
  8. IDE(4)——VS系列(4)——sln解决方案
  9. 翻译必考知识点总结+瑞思拜翻译知识点(3,4和5)
  10. 奥托尼克斯接近开关型号含义_AUTONICS圆形接近开关报价 奥托尼克斯圆形接近开关使用注意...