这篇博文我不讲委托和事件的概念,因为大段的文字概念没有任何意义。

具体想了解,委托和事件的概念可以MSDN查阅。

我这篇文章的主题思路是委托如何一步步进化成事件:

何为委托--->委托来实现事件--->用方法对委托的封装--->Event的

add,remove方法的引入--->标准事件写法--->反编译探究竟。

用几个例子以及Reflector反编译探究委托和事件的关系。不足之处,还望多多指教...

何为委托:

首先,委托是一种类型,是一种定义了方法签名的类型。

委托可以理解为函数指针(安全),并且委托约束了方法的签名(由返回类型和参数组成),

所以实例化委托时,可以将其实例与任何具有相同签名(由返回类型和参数组成)得方法相关联,

如果按照C语言函数指针理解,即委托实例指向某个方法。

为什么要用委托:

举个简单的例子:

例如,需要判断一个数是为奇数还是偶数?

可能我们会这样实现:

     static void Main(string[] args) { Console.WriteLine((4 % 2 == 0) ? "偶数" : "奇数"); Console.WriteLine((5 % 2 == 0) ? "偶数" : "奇数"); Console.ReadKey(); }

上面例子很简单,但是很不灵活,我们稍加改进:

static void Main(string[] args) { Console.WriteLine("请输入一个数字:"); int i = int.Parse(Console.ReadLine()); Console.WriteLine((i%2==0)?"偶数":"奇数"); Console.ReadKey(); }

上面这个简单的例子,也是挺有玄机的。对于程序员,我们不关心客户端用户传过来是奇数还是偶数,况且我们也不知道传过来的参数到底是多少,

我们只关心怎样来实现功能。对于用户来说,他们不必关心底层到底是怎样实现功能的,他们只负责输入数字即可“坐享其成”。这个例子,

可以理解成一个最简单的解耦。

  看了上面这个例子,我们再举一个例子来演示委托怎么替做什么:

  

    //委托是一种定义方法签名的类型。 当实例化委托时,可以将其实例与任何具有兼容签名的方法相关联。 可以通过委托实例调用方法。 //一个委托声明:public delegate void ChangeDelegate(int i); class Program { static void Main(string[] args) { ChangeDelegate c = null; if (DateTime.Now.Second%2==0) { c = Even;//委托可以理解为函数指针(安全),并且委托类型ChangeDelegate约束了参数类型,所以c可以指向Even方法
 c(DateTime.Now.Second); } else { //c = Odd;c = new ChangeDelegate(Odd);//标准写法
 c(DateTime.Now.Second); } Console.ReadKey(); } static void Even(int i) { Console.WriteLine("{0}是偶数",i); } static void Odd(int i) { Console.WriteLine("{0}是奇数",i); } }

上面代码可以看出,程序员并不知道委托实例到底指向那个函数,但他可以确定,指向的那个方法必定是受ChangeDelegate约束的。

再看一个例子,我们要对数组进行操作:

 class Program { static void Main(string[] args) { int[] arr = { 1,2,3,4,5,6,7,8,9}; List<int> newList=Filter(arr,IsOdd); Console.WriteLine(string.Join("-",newList.ToArray())); Console.ReadKey(); } /// <summary>/// 判断是否为偶数 /// </summary>/// <param name="i"></param>/// <returns></returns>static bool IsEven(int i) { return i%2==0; } /// <summary>/// 判断是否为奇数 /// </summary>/// <param name="i"></param>/// <returns></returns>static bool IsOdd(int i) { return i%2==1; } static List<int> Filter(int[] value, FilterDelegate f) { List<int> list=new List<int> (); foreach (var item in value) { if (f(item)) { list.Add(item); } } return list; } } delegate bool FilterDelegate(int i);

所以,static List<int> Filter(int[] value, FilterDelegate f),这儿只需要传过来一个方法,

而我们程序员并不关心这是个什么方法,能替我们做什么,这就是委托的好处。

  事件和委托的联系:学习事件之前,先来用委托来模拟实现事件:

 

    class Program { static void Main(string[] args) { Counter c = new Counter(); c.onCount = Count;//相当于订阅了一个事件c.onCount += Count_2;//可以多个人同时监听了int j = 0; while (j<=100) { j++; c.Next(); } Console.ReadKey(); } static void Count(int value) { Console.WriteLine("Count监听了{0}是偶数", value); } static void Count_2(int value) { Console.WriteLine("Count_2监听了{0}是偶数", value); } } class Counter { public OnCountDelegate onCount;//把委托对象声明为一个字段private int i = 0; public void Next() { i++; if (i%2==0) { if (onCount!=null) { //解耦:解除耦合。 //不用关心到底指向谁,调用就行onCount(i);//触发事件,调用onCount指向的函数,相当于把事件通知出去
 } } } } public delegate void OnCountDelegate(int value);

  c.onCount = Count;c.onCount += Count_2; 相当于监听事件,触发事件时,只要哦调用onCount指向的函数,这样相当于把事件通知出去。所以上面这个Demo之后,我们再可以对委托来实现事件进行扩展: 我们自定义一个双击火箭手按钮[用户控件]: 
namespace 双击火箭手按钮 { //声明一个委托public delegate void DoubleClickDelegate(); public partial class DoubleClickButton : UserControl { public DoubleClickButton() { InitializeComponent(); } private int i; //把一个的委托对象定义为Public字段public DoubleClickDelegate OnDoubleClick; private void button1_Click(object sender, EventArgs e) { i++; if (i==2) { i = 0; if (OnDoubleClick!=null) { OnDoubleClick();//调用事件的响应函数
 } } } } }

然后我们在Form1中托入一个我们自定义的DoubleClickButton:

这儿我们可以仿照普通Button按钮监听Click事件:  this.button1.Click += new System.EventHandler(this.button1_Click);来那样做:对DoubleClickButton的

OnDoubleClick事件进行监听:
        private void Form1_Load(object sender, EventArgs e) { doubleClickButton1.OnDoubleClick = doFire; doubleClickButton1.OnDoubleClick += doIce; } void doFire() { MessageBox.Show("双击火枪手开火"); } void doIce() { MessageBox.Show("双击火枪手下冰雨"); }

这样一个简单的用户控件就完成了,双击两下触发了OnDoubleClick事件,并且去执行相关联的响应函数(doFire,doIce)。

接着我们在对这个程序进行修改,来干扰我们的双击火枪手按钮:

我们在捣乱这个按钮的中写入:

        private void button1_Click(object sender, EventArgs e) { doubleClickButton1.OnDoubleClick = null; }

上面的操作意味着我们把委托变量指向了NULL,这就破坏了之前我们的监听事件。再比如:在模拟执行这个按钮中写入:
        private void button2_Click(object sender, EventArgs e) { doubleClickButton1.OnDoubleClick(); }

上面代码模拟执行了双击火枪后按钮,本来需要双击两下才能触发事件,而这儿可以直接去执行事件的响应函数。

所以为了防止外界对我的事件的干扰,我们把

public OnCountDelegate onCount;//把委托对象声明为一个字段

改为:

   //把委托申明为Private,防止外界直接=NULL或者OnDoubleClick()仿照事件private DoubleClickDelegate OnDoubleClick;

再对私有的委托用一个AddDoubleClick进行对外界的过滤,所以完整代码应该是这样的:

 //把委托申明为Private,防止外界直接=NULL或者OnDoubleClick()仿照事件private DoubleClickDelegate _OnDoubleClick; public void AddDoubleClick(DoubleClickDelegate d) { _OnDoubleClick += d; } private void button1_Click(object sender, EventArgs e) { i++; if (i==2) { i = 0; if (_OnDoubleClick!=null) { _OnDoubleClick();//调用事件的响应函数
 } } }

上面这样处理之后,我们的控件就不会被外界干扰了。

但是这样操作太复杂,所以微软为我们提供了更为简便的方式既 Event:

对上面的双击火枪手按钮在做稍微修改:

namespace 三击暴走按钮 { public delegate void RampageDelegate(); public partial class RampageThreeClickButton : UserControl { //定义一个私有的委托类型字段private RampageDelegate onRampage; //类似于属性那样对委托进行了封装public event RampageDelegate OnRampage { add { onRampage += value; } remove { onRampage -= value; } } private int count; public RampageThreeClickButton() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { count++; if (count==3) { if (onRampage!=null) { onRampage(); } count = 0; } } } }

再将定义好的暴走控件拖到Form1中:

后台代码是这样的:

       public Form1() { InitializeComponent(); } private void rampageThreeClickButton1_Load(object sender, EventArgs e) { //对事件进行注册,即监听事件,只能用+=,不用用=,这样防止了外界=NULL干扰rampageThreeClickButton1.OnRampage += doFire; //同理rampageThreeClickButton1.OnRampage += new RampageDelegate(doThunder); rampageThreeClickButton1.OnRampage += new RampageDelegate(doIce); } void doFire() { MessageBox.Show("烈焰之怒"); } void doThunder() { MessageBox.Show("上古雷霆"); } void doIce() { MessageBox.Show("极地冰雨"); }

现在还能干扰吗?当然不行:

OK,到目前为止,大家对委托和事件肯定有一个深刻的认识:

我们对事件进行反编译之后,相信一切疑问皆是浮云:

我们举一个标准的事件案例:

namespace DoubleKissinUButton { public delegate void KissinUDelegate();//委托别忘记public partial class KissinUButton : UserControl { public event KissinUDelegate onKissinU;//用Event关键字来申明一个事件public KissinUButton() { InitializeComponent(); } private int i = 0; private void button1_Click(object sender, EventArgs e) { i++; if (i==2) { if (onKissinU!=null) { onKissinU(); } } } } }

界面:

 public partial class Form1 : Form { public Form1() { InitializeComponent(); kissinUButton1.onKissinU += new KissinUDelegate(kissinUButton1_onKissinU); } void kissinUButton1_onKissinU() { MessageBox.Show("点我我就吻吻你"); } private void Form1_Load(object sender, EventArgs e) { } }

通过反编译看看:

点击进入看看:

委托和事件没有可比性,因为委托是类型,事件是对象,上面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别。事件的内部是用委托实现的。 因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Delegate就没法进行上面的控制,因此诞生了事件这种语法。add、remove。

事件是用来阉割委托实例的。事件只能add、remove自己,不能赋值。事件只能+=、-=,不能=、不能外部触发事件。

转载于:https://my.oschina.net/OceanEyes/blog/381441

庖丁解牛——深入解析委托和事件相关推荐

  1. 庖丁解牛看委托和事件(续)

    上一篇文章:庖丁解牛--深入解析委托和事件之后,以一题面试题来总结事件 using System; using System.Collections.Generic; using System.Lin ...

  2. 委托与事件_从有趣的例子出发去解析

    曾经自以为掌握了委托与事件的关系及区别,然而看起来并没有.其实有很多知识,只是我们觉得自己掌握了,但是事实上我们真正的掌握了吗? 本文会从有趣的比喻出发来理解委托与事件的关系: 首先,先把官方的概念贴 ...

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

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

  4. C#委托和事件(3)

    面试例题4:举例说明匿名方法. 考点:匿名方法的作用,匿名方法的使用方法. 出现频率:★★★ 解答 匿名方法用于简化事件注册方法的编写过程,可以直接将方法体的代码和委托对象相关联而不需要单独定义这个方 ...

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

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

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

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

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

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

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

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

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

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

最新文章

  1. 【73套】Epic Stock Media配乐音效素材合集包
  2. 诊断IIS中的ASP0115错误
  3. 轻量级NLP工具开源,中文处理更精准,超越斯坦福Stanza
  4. Mac OS X 创新卡关三年,唯一看得出版本不同之处是「预设桌布」
  5. (C#) 调用执行批处理文件
  6. SuperMap产权登记管理平台
  7. MS SQL巡检系列mdash;mdash;检查重复索引
  8. 安卓怎么调用系统的ui_安卓逆向 | 为了反射调用我们怎么能拿到被HOOK函数的实例...
  9. Python使用BoundedSemaphore对象进行线程同步
  10. gradle项目启动报错_如何用IDEA创建SpringBoot Gradle多项目工程?
  11. Linux安装docker-ce教程 centos依赖包安装
  12. 几种基本汇编指令详解
  13. Windows Embedded Standard 7 快速入门指南 2 of 4
  14. 中国最小黑客:为不做作业 黑掉学校系统
  15. OmniGraffle 制作表格 调整对象
  16. 6-2 有序顺序表的插入
  17. 目标检测, 实例分割, 图像分类, panoptic segmentation文献
  18. Spec Explorer 2010
  19. 金融企业邮箱发推荐信,金融行业如何保障邮件安全?
  20. 苹果屏幕尺寸_搭载 mini LED 屏幕的 iPad Pro 要来了?!

热门文章

  1. 快手资讯|快手推出多档世界杯相关节目
  2. jsonp请求响应成功,但进入到error函数
  3. 超全装饰 陈设ps后期素材素材网站整理
  4. 舟山景区概况 舟山旅游项目介绍
  5. 45.帧缓冲设备(Framebuffer),LCD
  6. py实战绘制人口金字塔图
  7. java砍价源码_(JAVA)仿拼多多砍价算法
  8. ios手机页面滑动卡顿问题
  9. PS作业【利用新蒙版再生图像】的一些经验和提示
  10. 【Python学习笔记】3. Python3 基础语法