0

0

C#委托,事件理解入门

黄舟

黄舟

发布时间:2016-12-21 14:54:05

|

1160人浏览过

|

来源于php中文网

原创

目录 

l        导论 

l        什么是委托 

l        事件的理解 

l        事件 关键字 

l        最后 

  

导论 

    在学习c#中的委托和事件过程中,我读了许多文章来理解他们二者究竟是怎么一回事,以及如何使用他们,现在我将整个的理解过程陈述以下,我学到的每一方面,恐怕也是你们需要掌握的 :-)。 

什么是委托? 

    委托和事件这两个概念是完全配合的。委托仅仅是函数指针,那就是说,它能够引用函数,通过传递地址的机制完成。委托是一个类,当你对它实例化时,要提供一个引用函数,将其作为它构造函数的参数。 

  每一个委托都有自己的签名,例如:delegate int somedelegate(string s, bool b);是一个委托申明,在这里,提及的签名,就是说somedelegate 这个委托 有 string 和 bool 类型的形参,返回一个int 类型。 

上面提及的:当你对委托实例化时,要提供一个引用函数,将其作为它构造函数的参数。这里要注意了:被引用的这个函数必须和委托有相同的签名。 

看下面的函数: 

private int somefunction(string str, bool bln){...} 

你可以把这个函数传给somedelegate的构造函数,因为他们有相似的签名(in other words,他们都有相同的形参类型和个数,并且返回相同的数据类型)。 

    somedelegate sd = new somedelegate(somefunction); 

  sd 引用了 somefunction,也就是说,somefunction已被sd所登记注册,如果你调用 sd,somefunction 这个函数也会被调用,记住:我所说 somefunction的含义,后面,我们会用到它。 

  现在,你应该知道如何使用委托了,让我们继续理解事件之旅…… 

事件的理解 

我们知道,在c#中: 

l        按钮(button)就是一个类,当我们单击它时,就触发一次click事件。 

l        时钟(timer)也是一个类,每过一毫秒,就触发一次tick事件。 


让我们通过一个例子来学习,假定有这样的情节: 

  现在有一个counter的类,它有一个方法 countto(int countto, int reachablenum),该方法表示:在指定的时间段内(0~~countto),当到达指定的时间点reachablenum时,就触发一次numberreached事件。 

它还有一个事件:numberreached,事件是委托类型的变量。意思是:如果给事件命名,用event关键字和要使用的委托类型申明它即可,如下所示: 

public event numberreachedeventhandler numberreached; 

  

在上面的申明中,numberreachedeventhandle 仅是一个委托,更确切的表示应该是:numberreacheddelegate。但是微软从不这样认为mousedelegate或者paintdelegate,,而是称谓:mouseeventhandler 或者 painteventhandler。所以 

numberreachedeventhandler 比numberreacheddelegate听起来更方便一些,ok?好了,让我们继续,现在你知道了,在我们声明事件之前,需要象下面这样的形式来定义委托: 

public delegate void numberreachedeventhandler(object sender, numberreachedeventargs e); 

现在声明的委托 numberreachedeventhandle,它有一个void 返回值,和object,numberreachedeventargs两个形参。就像我们在第一节中强调的那样,当实例化委托时,作为实参传入的函数也必须拥有和委托同样的签名。 

在你的代码中, 你是否用过painteventargs 或者 mouseeventargs来确定鼠标的移动位置?是否在触发paint事件的对象中用过graphics 属性?实际上,为用户提供数据的类都是继承于system.eventargs类,就是我们常说的事件参数类,如果事件不提供参数,就不定义该类。在我们的例子中,我们通过下面的类提供预期的时间点。 

public class numberreachedeventargs : eventargs 



    private int _reached; 

    public numberreachedeventargs(int num) 

    { 

        this._reached = num; 

    } 

    public int reachednumber 

    { 

        get 

        { 

            return _reached; 

        } 

    } 



好,有了前面的介绍,让我们到counter类里面看看: 

namespace events 



    public delegate void numberreachedeventhandler(object sender, 

        numberreachedeventargs e); 

  

    ///

 

    /// summary description for counter. 

    ///
 

    public class counter 

    { 

        public event numberreachedeventhandler numberreached; 

        

        public counter() 

        { 

            // 

            // todo: add constructor logic here 

            // 

        } 

        public void countto(int countto, int reachablenum) 

        { 

            if(countto
                throw new argumentexception( 

                    "reachablenum should be less than countto"); 

            for(int ctr=0;ctr
            { 

                if(ctr == reachablenum) 

                { 

                    numberreachedeventargs e = new numberreachedeventargs( 

                        reachablenum); 

                    onnumberreached(e); 

                    return;//don't count any more 

                } 

            } 

        } 

  

        protected virtual void onnumberreached(numberreachedeventargs e) 

        { 

            if(numberreached != null) 

            { 

                numberreached(this, e);//raise the event 

            } 

        } 



在counter中,如果到达指定的时间点,就触发一次事件,有以下几个方面需要注意: 

l        通过调用numberreached(它是numberreachedeventhandler委托的实例)来完成一次触发事件。 

numberreached(this, e);  通过这种方式,可以调用所有的注册函数。 

l        通过 numberreachedeventargs e = new numberreachedeventargs(reachablenum); 为所有的注册函数提供事件数据。 

l        看了上面的代码,你可能要问了:为什么我们直接用 onnumberreached(numberreachedeventargs e)方法来调用numberreached(this,e),而不用下面的代码呢? 

    if(ctr == reachablenum) 



    numberreachedeventargs e = new numberreachedeventargs(reachablenum); 

    //onnumberreached(e); 

    if(numberreached != null) 

    { 

        numberreached(this, e);//raise the event 

    } 

    return;//don't count any more 



这个问题问得很好,那就让我们再看一下onnumberreached 签名: 

protected virtual void onnumberreached(numberreachedeventargs e) 

①你也明白 关键字protected限定了 只有从该类继承的类才能调用该类中的所有方法。 

②关键字 virtual 表明了 在继承类中可以重写该方法。 

这两点非常有用,假设你在写一个从counter继承而来的类,通过重写onnumberreached 方法,你可以在事件触发之前,进行一次其他的工作。 

  

protected override void onnumberreached(numberreachedeventargs e) 



    //do additional work 

    base.onnumberreached(e); 



注意:如果你没有调用base.onnumberreached(e), 那么从不会触发这个事件!在你继承该类而想剔出它的一些其他事件时,使用该方式是非常有用的。 

l        还要注意到:委托 numberreachedeventhandler 是在类定义的外部,命名空间内定义的,对所有类来说是可见的。 

好,该我们来实际操作使用counter类了。 

  

在我们简单的应用程序中,我们有两个文本框,分别是:txtcountto和txtreachable: 




下面是btnrun的click事件: 

private void btnrun_click(object sender, system.eventargs e) 

       { 

           if(txtcountto.text == "" || txtreachable.text=="") 

              return; 

           ocounter.countto(convert.toint32(txtcountto.text), convert.toint32(txtreachable.text)); 

       } 

  

private void ocounter_numberreached(object sender, numberreachedeventargs e) 

       { 

           messagebox.show("reached: " + e.reachednumber.tostring()); 

   } 

  

初始化事件处理的语法如下: 

ocounter = new counter(); 

          ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached); 

          

现在你明白了你刚才所做的一切,仅仅初始化 numberreachedeventhandler 委托类型的对象(就像你实例化其他对象一样),注意到 ocounter_numberreached 方法的签名与我前面提到的相似。 

还要注意我们用的是+= 而不是=;这是因为委托是特殊的对象,它可以引用多个对象(在这里是指它可以引用多个函数)。for example 如果有另外一个 

和ocounter_numberreached一样具有相同签名的函数ocounter_numberreached2,这两个函数都可以被引用: 

  

ocounter = new counter(); 

           ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached); 

           ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached2); 

现在,触发一个事件后,上面两个函数被依次调用。 

  

视情况而定,如果你想让ocounter_numberreached2在numberreached事件发生后不再被调用,可以简单地这样写:ocounter.numberreached -= new numberreachedeventhandler(ocounter_numberreached2); 

  

最后   让我们看一下完整的源代码,以供参考: 


form1.cs 


using system; 
using system.drawing; 
using system.collections; 
using system.componentmodel; 
using system.windows.forms; 
using system.data; 

namespace events 

    /**////  
    /// summary description for form1. 
    ///
 
    public class form1 : system.windows.forms.form 
    { 
        counter ocounter = null; 

        private system.windows.forms.button cmdrun; 
        private system.windows.forms.textbox txtreachable; 
        private system.windows.forms.textbox txtcountto; 
        private system.windows.forms.label label1; 
        private system.windows.forms.label label2; 
        private system.windows.forms.button btnremovedelegate; 
        /**////  
        /// required designer variable. 
        ///
 
        private system.componentmodel.container components = null; 

        public form1() 
        { 
            // 
            // required for windows form designer support 
            // 
            initializecomponent(); 

            // 
            // todo: add any constructor code after initializecomponent call 
            // 
            ocounter = new counter(); 
            ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached); 
            ocounter.numberreached += new numberreachedeventhandler(ocounter_numberreached2); 
        } 

        /**////  
        /// clean up any resources being used. 
        ///
 
        protected override void dispose( bool disposing ) 
        { 
            if( disposing ) 
            { 
                if (components != null)  
                { 
                    components.dispose(); 
                } 
            } 
            base.dispose( disposing ); 
        } 

        windows form designer generated code#region windows form designer generated code 
        /**////  
        /// required method for designer support - do not modify 
        /// the contents of this method with the code editor. 
        ///
 
        private void initializecomponent() 
        { 
            this.cmdrun = new system.windows.forms.button(); 
            this.txtreachable = new system.windows.forms.textbox(); 
            this.txtcountto = new system.windows.forms.textbox(); 
            this.label1 = new system.windows.forms.label(); 
            this.label2 = new system.windows.forms.label(); 
            this.btnremovedelegate = new system.windows.forms.button(); 
            this.suspendlayout(); 
            //  
            // cmdrun 
            //  
            this.cmdrun.location = new system.drawing.point(16, 72); 
            this.cmdrun.name = "cmdrun"; 
            this.cmdrun.size = new system.drawing.size(48, 23); 
            this.cmdrun.tabindex = 2; 
            this.cmdrun.text = "run"; 
            this.cmdrun.click += new system.eventhandler(this.cmdrun_click); 
            //  
            // txtreachable 
            //  
            this.txtreachable.location = new system.drawing.point(144, 40); 
            this.txtreachable.name = "txtreachable"; 
            this.txtreachable.size = new system.drawing.size(56, 20); 
            this.txtreachable.tabindex = 1; 
            this.txtreachable.text = ""; 
            //  
            // txtcountto 
            //  
            this.txtcountto.location = new system.drawing.point(144, 16); 
            this.txtcountto.name = "txtcountto"; 
            this.txtcountto.size = new system.drawing.size(56, 20); 
            this.txtcountto.tabindex = 0; 
            this.txtcountto.text = ""; 
            //  
            // label1 
            //  
            this.label1.autosize = true; 
            this.label1.location = new system.drawing.point(16, 16); 
            this.label1.name = "label1"; 
            this.label1.size = new system.drawing.size(51, 13); 
            this.label1.tabindex = 3; 
            this.label1.text = "count to"; 
            //  
            // label2 
            //  
            this.label2.autosize = true; 
            this.label2.location = new system.drawing.point(16, 40); 
            this.label2.name = "label2"; 
            this.label2.size = new system.drawing.size(99, 13); 
            this.label2.tabindex = 4; 
            this.label2.text = "reach this number"; 
            //  
            // btnremovedelegate 
            //  
            this.btnremovedelegate.location = new system.drawing.point(16, 104); 
            this.btnremovedelegate.name = "btnremovedelegate"; 
            this.btnremovedelegate.size = new system.drawing.size(168, 23); 
            this.btnremovedelegate.tabindex = 5; 
            this.btnremovedelegate.text = "remove second handler"; 
            this.btnremovedelegate.click += new system.eventhandler(this.btnremovedelegate_click); 
            //  
            // form1 
            //  
            this.autoscalebasesize = new system.drawing.size(5, 13); 
            this.clientsize = new system.drawing.size(224, 134); 
            this.controls.addrange(new system.windows.forms.control[] { 
                                                                          this.btnremovedelegate, 
                                                                          this.label2, 
                                                                          this.label1, 
                                                                          this.txtcountto, 
                                                                          this.txtreachable, 
                                                                          this.cmdrun}); 
            this.name = "form1"; 
            this.text = "events"; 
            this.resumelayout(false); 

        } 
        #endregion 

        /**////  
        /// the main entry point for the application. 
        ///
 
        [stathread] 
        static void main()  
        { 
            application.run(new form1()); 
        } 

        private void btnrun_click(object sender, system.eventargs e) 
        { 
            if(txtcountto.text == "" || txtreachable.text=="") 
                return; 
            ocounter.countto(convert.toint32(txtcountto.text), convert.toint32(txtreachable.text)); 
        } 

        private void ocounter_numberreached(object sender, numberreachedeventargs e) 
        { 
            messagebox.show("reached: " + e.reachednumber.tostring()); 
        } 
        private void ocounter_numberreached2(object sender, numberreachedeventargs e) 
        { 
            messagebox.show("reached2: " + e.reachednumber.tostring()); 
        } 

        private void btnremovedelegate_click(object sender, system.eventargs e) 
        { 
            ocounter.numberreached -= new numberreachedeventhandler(ocounter_numberreached2); 
            ocounter.countto(convert.toint32(txtcountto.text), convert.toint32(txtreachable.text)); 
        } 
    } 

  






counter.cs 


  

using system; 

namespace events 

    public delegate void numberreachedeventhandler(object sender, numberreachedeventargs e); 

    /**////  
    /// summary description for counter. 
    ///
 
    public class counter 
    { 
        public event numberreachedeventhandler numberreached; 
         
        public counter() 
        { 
            // 
            // todo: add constructor logic here 
            // 
        } 
        public void countto(int countto, int reachablenum) 
        { 
            if(countto                 throw new argumentexception("reachablenum should be less than countto"); 
            for(int ctr=0;ctr            { 
                if(ctr == reachablenum) 
                { 
                    numberreachedeventargs e = new numberreachedeventargs(reachablenum); 
                    onnumberreached(e); 
                    return;//don't count any more 
                } 
            } 
        } 

        protected virtual void onnumberreached(numberreachedeventargs e) 
        { 
            if(numberreached!=null) 
            { 
                numberreached(this, e); 
            } 
        } 
    } 

    public class numberreachedeventargs : eventargs 
    { 
        private int _reached; 
        public numberreachedeventargs(int num) 
        { 
            this._reached = num; 
        } 
        public int reachednumber 
        { 
            get 
            { 
                return _reached; 
            } 
        } 
    } 

 以上就是C#委托,事件理解入门的内容,更多相关内容请关注PHP中文网(www.php.cn)! 

Video Summarization
Video Summarization

一款可以自动将长视频制作成短片的桌面软件

下载

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

109

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

16

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

136

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

7

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

6

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

122

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

35

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

121

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 3万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号