惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
AI
AI
博客园 - 三生石上(FineUI控件)
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
雷峰网
雷峰网
NISL@THU
NISL@THU
S
Schneier on Security
T
Threatpost
T
Tenable Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
IT之家
IT之家
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
C
Cybersecurity and Infrastructure Security Agency CISA
P
Privacy & Cybersecurity Law Blog
I
Intezer
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
T
Threat Research - Cisco Blogs
SecWiki News
SecWiki News
AWS News Blog
AWS News Blog
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
V
V2EX
Recorded Future
Recorded Future
Microsoft Security Blog
Microsoft Security Blog
S
Secure Thoughts
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
Apple Machine Learning Research
Apple Machine Learning Research
Project Zero
Project Zero
PCI Perspectives
PCI Perspectives
G
GRAHAM CLULEY
Help Net Security
Help Net Security
Cloudbric
Cloudbric
Recent Announcements
Recent Announcements
V
Visual Studio Blog
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
C
CERT Recently Published Vulnerability Notes
The Cloudflare Blog
Forbes - Security
Forbes - Security
C
Cisco Blogs
O
OpenAI News
www.infosecurity-magazine.com
www.infosecurity-magazine.com

博客园 - maledong

如何通过反射调用扩展方法? JQuery学习笔记——nt-child的使用 - maledong - 博客园 求最大公约数与最小公倍数的算法 ASP.NET专题研究——角色和Profile ASP.NET专题研究——用户登录、注册和发送密码 ASP.NET专题研究——登录权限 C#4.0和VS2010新特性(三) C#4.0和VS2010新特性(二) C#4.0和VS2010新特性(一) F# 快乐之旅(一)——F#尝鲜 MVC专题研究(五)——数据验证 MVC专题研究(四)——Html中的扩展方法 MVC专题研究(三)——数据绑定和传送 MVC专题研究(二)——神奇的URL MVC2专题研究(一)——用MVC组织管理您的家庭收入 典型算法及应用——“递归法”探究 ASP.NET专题研究——资源文件的使用 NET基本探究系列——委托 NET常见类系列探究——序列化和反序列化的应用
NET基本探究——事件
maledong · 2010-04-20 · via 博客园 - maledong

(一)事件委托”:

            在“NET基本探究系列”委托的部分我们已经知道了委托的出现为不同类之间动态调用同参、同返回值的函数提供了便利。现在我们来进一步研究委托在实际开发中的例子——事件(event)。

            我们只要是用NET开发的就一直不断在接触事件——举个最简单的例子就是你在WinForm上拉一个Button,然后双击就出现一个“事件函数”。这个“事件函数”的本质是和“事件”挂钩的。如果你查看InitializeComponent()这部分的代码,你会发现有这样一行东西:

   private void InitializeComponent()

        {

            this.button1 = new System.Windows.Forms.Button();

            this.SuspendLayout();

……

            this.button1.Click += new System.EventHandler(this.button1_Click);

      }

注意上述代码中黑色的部分:其中Click是一个Button的事件,而“+=”(VB中是AddressOf)类似于为Click事件指明触发函数(在本文件的button1_Click)。

如果你右键查看Click的定义,你会发现Button类的Click事件的定义:

public event EventHandler Click;

而如果你再“刨根问底”下去,会发现Click的类型是EventHandler,而这恰恰又是一个委托。正是因为“委托”具备不同类之间允许动态调用同参同返回值函数的功能,所以你在一个Form类上引入Button类(拖拽一个Button到上面),双击Button之后在Form类自身生成一个与Button事件委托同参同返回值的私有函数,同时把这个函数和事件使用“+=”的形式挂接起来,完成了事件函数的初始化操作。至此,我们可以得出这样一个结论:“事件”和“委托”是密不可分的——“事件”恰恰利用了委托的“动态函数”特性使得你可以在不同类之间调用同参同返回值的函数,以便达到“触发”的效果。同时,我们也知道了一般事件定义方法:public event 委托类型名 事件名;——注意,委托类型必须是无返回值的,即void类型。 

我们可以把“事件”的初始化和“委托”的初始化加以对比,增强我们对于它们之间关系理解的记忆:

委托:   EventHander eh = new EventHander (同参同返回类型函数名)

事件:XXX.Click  +=  new 事件委托名 (同参同返回类型函数名)

请特别注意我放大的这个部分:既然事件的本质是委托,为何不像委托一样使用等于符号,而偏偏使用“+=”进行初始化操作呢?这里就牵涉到了“隐式事件声明”的概念:一般地,任何在NET中的事件都是一个事件列表,通过已经重载的“+=”对事件进行批量的增加或者删除操作。为了解释清楚这个概念,现在我们“+=”代码展开让读者看看,NET究竟背后“秘密地”干了些什么——

(二)显示声明的“事件”:

我们注意到一个非常有意思的现象——如果你把一个类的事件(比如Button)同时指向(绑定到一个以上)的事件函数中的时候:

   private void InitializeComponent()

        {

            this.button1 = new System.Windows.Forms.Button();

            this.SuspendLayout();

……

            this.button1.Click += new System.EventHandler(this.button1_Click);

this.button1.Click += new System.EventHandler(this.button2_Click);  //自己对应添加一个Button方法

      }

            此时,如果你在button1_click中写上了弹出显示“1”的msgbox,然后在button2_click同时写上弹出“2”的对话框,你会“惊讶地”发现不是仅仅弹出2,而是“先1后2”!——Why?难道“事件”天性有记忆力?

            如果我们回顾“多路委托”的概念的时候,知道一个委托可以加载多个同参同返回值的委托函数;同样地,一个事件也可以像委托一样进行“多路事件”的加载,只是微软在每一个事件背后本质上做了这样一些东西(拿Button作例子):

            public class Button

            {

                        private List<EventHandler> clickevents = new List<EventHandler>();

                        public event EventHandler Click

                        add

                        {

                                    clickevents.Add(value);

                        }

                        remove

                        {

                                    clickevents.Remove(value);

                        }

                        public void OnClick()

                        {

                                    foreach (var item in clickevents)

                                    {

                                                item(this,null);   //此处自行调用事件,表明到OnClick函数被执行后触发相应挂接的事件函数。

                                    }

                        }

            }

            这个定义看上去很像属性,但是和属性不一样的在于“事件属性”多出了两个特殊的关键词“add”和“remove”,其本质是对“+=”和“-=”的重载定义:即用“+=”挂接到一个新函数时候,自动委派执行add中的Add方法,把真正执行的函数通过value传递并且添加到clickevents列表中。反之,使用“-=”,会自动执行remove,去掉已经定义的事件函数,从事件列表中移除。这样,当你点击了一个Button的时候,系统自然调用OnClick类似的函数,然后从事件列表中依次执行已经添加的事件函数。事件的“记忆性”就是这样形成的。

    实际上,你完全可以按照这种方式,自行添加一个事件列表去有选择地控制事件的执行。不信你可以试一试。