必威体育Betway必威体育官网
当前位置:首页 > IT技术

C# 中的委托和事件(详解:简单易懂的讲解)

时间:2019-10-12 09:13:19来源:IT技术作者:seo实验室小编阅读:56次「手机版」
 

c#委托

本文转载自 http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html

C# 中的委托和事件(详解)

https://www.cnblogs.com/newcapecjmc/p/7084026.html

基础:https://www.cnblogs.com/hongfei/p/3574239.html

中级:http://www.tracefact.net/tech/009.html

https://blog.csdn.net/yijun494610095/article/details/62422746

进阶:https://www.cnblogs.com/sjqq/p/6917497.html

关于委托和事件分享三个博客内容

首先说明下:

(1)C#中事件:事件时属于类的成员,所以要放在类的内部。

(2)委托属于一个定义,是和类、接口类似的,通常放在外部。

(因为大多数委托都要被重用)

委托定义在类里面还是类外面视情况而定,一般定义在与类定义平级部分,

且用public修饰,便于外部调用。

若定义在类的内部,则必须通过调用该类的成员才能取得其委托的引用,

频繁调用的情况下不合适。

*委托定义在类内部,举例说明如下:

Class A {

 //声明在这里是可以的~

 private delegate void test_del(int a);

 

 private void test(){...}

 public void start(){

//声明在这里就不行了~

private delegate void test_del(int a);

}

}

委托是一种特殊的类,和普通类不同的是委托是对一类方法的抽象。

因此只能在类内部定义内部类(包括委托、结构和枚举)而不能在方法中定义

第一个:

再谈C#委托与事件

转自:http://ruizhinet.blog.163.com/blog/static/9921382820092801032681/

之前写过一篇关于C#委托与事件的文章(见《C#委托和事件例析》),不过还是收到一些网友的提问。所以,今天再换另一个角度来详解一下这个问题。

一、在控制台下使用委托和事件

我们都知道,C#中有“接口”这个概念,所谓的“接口”就是定义一套标准,然后由实现类来具体实现其中的方法,所以说“接口,是一组类的抽象”。同样道理,我们可以将“委托”理解为“方法的抽象”,也就是说定义一个方法的模板,至于这个方法具体是怎么样的,就由方法自己去实现。

我们知道接口的最大好处就是可以实现多态,同理,“委托”是可以实现方法的多态,当我们想调用某个具体方法的时候,我们不直接调用这个方法,而是去调用这个委托。当然,我们必须在具体方法和委托之间建立某种关联。

下面我们来看例子。

首先,我们定义一个委托:

public delegate void SaySomething(string name);

这跟抽象方法的语法格式很相似,只是多了一个关键字delegate。既然是对方法的一种抽象,那么我们最关注的当然就是方法的返回值以及方法的参数了。所以上面红色的部分就是我们定义出来的一个规矩,如果某个方法想委托我去做事,那么请你遵循我的规矩,就是返回值为void,参数为一个字符串。我们这个委托的含义是,当某个人来了,就向他说点东西。

好,既然我们已经定义了这个规矩,下面我们就定义具体的方法了。

public void SayHello(string name) {     console.WriteLine("Hello," + name + "!"); }

public void SayNiceToMeetYou(string name) {     Console.WriteLine("Nice to meet you," + name + "!"); }

我们这里一共定义了两个方法,一个是向某人说Hello,另一个是向某人说Nice to meet you。我们看到,这里定义的两个方法的返回值和参数跟我们前面定义的“委托”是一致的。

接下来,我们来看事件。

public event SaySomething come;

我们定义了一个事件,这个事件是“有人来了”,注意定义的时候我们使用event关键字,除此之外,我们还加上了前面定义的“委托”的名字。这个意思是说,我这个事件只会跟“SaySomething”打交道,并且,当我这个事件发生的时候,我会通知关注我的这些“委托”(再由这些“委托”去调用具体的方法)。

我们来定义一个测试方法:

public void test() {      SaySomething sayhello = new SaySomething(SayHello);     SaySomething saynice = new SaySomething(SayNiceToMeetYou);     come += sayhello;     come += saynice;     come("张三"); }

方法体中的前面两行是用来实例化委托,注意我们用到了new关键字,就好像实例化一个类一样,然后传入一个参数,但这个参数不是string类型、也不是int类型,而是一个方法名。

再下面两行就是将委托加到事件上,意思是说,如果你这个事件发生了,就告诉我一声。可以通过“+=”来将n个委托实例加到某个事件上,一旦这个事件发生,所有的这些委托实例都会得到通知。

最后一行是触发一个事件,注意我们是直接用一个事件名,然后跟一个参数,这又跟“委托”中定义的那个规矩一致(即,要有一个string类型的参数)。

最后运行一下

static void Main(string[] args) {     Program program = new Program();     program.test();     Console.Read(); }

我们回过头来再看一下“事件”的定义:

public event SaySomething come;

这里已经指出了“委托”的名字,所以,我们可以直接将方法加到事件上,而省略“委托”的实例化过程,因此上面的test()方法可以简单写为:

public void test() {      come += SayHello;     come += SayNiceToMeetYou;     come("张三"); }

二、在窗体中使用委托和事件

上面的例子并不能体现委托和事件的优点,其实,委托和事件在C#中使用非常广泛,例如,当我们点击某个“按钮”的时候,就会有一个“Click”事件触发,而这个事件会通知“委托”,在C#窗体应用程序中,“委托”的名字比较规范,统一使用“eventhandler”,它的具体格式是“void EventHandler(object sender, EventArgs e);”。相信大家都写过下面这样子的HelloWorld程序:

当点击按钮的时候弹出一个对话框。我们怎样实现的呢?你肯定会说,我们在设计窗口双击按钮,就会自动为我们生成类似如下的方法:

private void button1_Click(object sender, EventArgs e) {     messageBox.Show("我被点击了!!!"); }

其实,这里用到的就是事件和委托,这里的button1_Click就是符合EventHandler委托规矩的一个具体的方法,即返回值为void,参数分别是一个object和EventArgs。

我们可以在Form1.Designer.cs中看到如下代码

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

可以看到,这里有一个Click事件,然后将一个委托实例附加到这个事件上,跟我们前面讲的控制台应用程序中的用法是完全一样的。那这个Click事件是怎么触发的呢?对于这些系统类的事件,并不用我们管。

当然,我们也可以定义自己的事件和委托,例如我定义一个事件,这个事件就是输出对象的名字。

我们这里定义了一个ShowName委托和一个btnclick事件。并且,在button1_Click()方法中触发这个btnclick事件。最后的结果是,当我们点击按钮的时候,首先弹出一个“我被点击了!!!”的对话框,然后确定之后再弹出另一个显示按钮名称的对话框:

第二个 

C#委托和事件例析  

ah_bill是对java了解相对较多,而对C#则是因工作需要才去看了一下,C#跟Java在语法上非常相似,而最初让我比较困惑的就是委托、事件部分,相信大多数初学者也有类似的困惑。经过跟Java的对比学习,发现这其实跟Java的监听、事件是等同的,只是表述上不同罢了。

委托+事件是观察者模式的一个典型例子,所谓的委托其实就是观察者,它会关心某种事件,一旦这种事件被触发,这个观察者就会行动。

下面是最近写的一个例子,相信能够加深大家对委托和事件的理解。

using System; using System.Collections.Generic; using System.Text;

namespace ConsoleAPPlication3

{    

public delegate void TimeEventHandler(object obj, TimeEventArgs  args); //定义一个委托,委托其实就是“方法模板”,就好像“类”是“对象”的模板一样。如果某个类想在事件触发的时候收到通知,它必须有一个符合这种格式的方法,在这个例子中,就是:返回类型为void,参数类型为object、TimeEventArgs。

//TimeEventArgs是我们自己定义的一个类,用于保存事件中的参数。这里我们分别保存时间的时分秒。

   public class TimeEventArgs:EventArgs

  {        

  private int hour;        

  private int minute;

         private int second;        

 public TimeEventArgs(int hour, int minute, int second)       

    {            

            this.hour = hour;            

            this.minute = minute;            

            this.second = second;      

      }        

    public int Hour        

    {            

            get           

           {                

                return hour;            

         }        

 }        

public int Minute        

       {            

             get            

              {                

                return minute;            

             }        

      }        

public int Second        

     {            

           get            

           {                

             return second;        

          }        

   }    

}

//这是一个观察者类,它有一个符合我们上面定义的“委托”的方法,也就是void ShowTime(object obj, TimeEventArgs args),从这个方法的定义可以看到,我们只会关心返回类型和方法的参数,而方法名称则无所谓。

  class MyTimeEventHandlerClass    

{        

public void ShowTime(object obj, TimeEventArgs args)        

{            

  Console.WriteLine("现在的时间是:"+args.Hour+":"+args.Minute+":"+args.Second);        

}    

}

//时钟类     class Clock    

    {

//我们在这个类中定义了一个“TimeChanged”事件,注意其前面有两个关键字“event”和“TimeEventHandler”,其中event表示这是一个事件,而不是方法或属性;TimeEventHandler则指出,谁要监听TimeChanged事件,它就必须有一个符合TimeEventHandler(委托)的方法。        

           public event TimeEventHandler TimeChanged;        

           public Clock()        

           {            

                   TimeChanged = null; //注意,这里的null的含义是指TimeChanged事件当前还没有观察者关注它,如果某个观察者要关注TimeChanged事件,它必须要让这个事件知道,方法是使用操作符“+=”来借助委托将其加载到事件上。        

           }

//时钟开始走动,我们的目标是每秒钟触发一次TimeChanged事件        

        public void go()        

         {            

                   DateTime initi = DateTime.Now;            

                   int h1 = initi.Hour;            

                   int m1 = initi.Minute;            

                   int s1 = initi.Second;            

                   while (true)            

                    {                

                         DateTime now = DateTime.Now;                

                         int h2 = now.Hour;                

                         int m2 = now.Minute;                

                         int s2 = now.Second;                

                           if (s2!=s1)                

                             {                    

                                  h1 = h2;                    

                                  m1 = m2;                    

                                   s1 = s2;

//首先建立一个TimeEventArgs对象来保存相关参数,这里是时分秒。                    

TimeEventArgs args = new TimeEventArgs(h2,m2, s2);

//注意这种写法,这一句是用来触发事件,事件不是类,所以不用使用“new”关键字,而且我们看到,这里TimeChanged的两个参数跟我们的委托(TimeEventHandler)是一致的,其中第一个参数是触发这个事件的对象,我们这里使用的是一个时钟实例(this)。

                                 TimeChanged(this, args);             

                            }            

                   }        

          }    

  }

   class Program    

   {

   static void Main(string[] args)        

{            

    Clock clock = new Clock(); //实例化一个时钟            

    MyTimeEventHandlerClass tehc = new MyTimeEventHandlerClass(); //实例化一个观察者类

//将事件跟我们定义的观察者进行连接,这样,clock就会知道,每当TimeChanged事件被触发,就会去通知这个观察者,注意我们连接的时候使用的并不是直接的观察者类实例中的ShowTime()方法,而是一个委托,并在这个委托中传递ShowTime()方法,这也是“委托”的真正意义所在——我有一个方法,但我委托你来帮我关联到事件,因为事件只会直接跟委托打交道,而不是观察者的具体某个方法。            

     clock.TimeChanged+=new TimeEventHandler(tehc.ShowTime);            

     clock.go();        

  }    

   }

}

第三个博文:

C#中的委托到底是什么概念??

委托,简单理解是这样的.

比如您要管您的孩子,把孩子送进了幼儿园.

OK.此时您就把您的孩子委托给了幼儿园.

当幼儿园放学,将孩子交还给您的手中.则是委托的回调.

当然我这里的例子是说异步委托调用.您也可以同步.

什么是同步委托调用?

您去银行存钱.把钱给柜员.他们帮你点钞.存款然后给您存折或卡.

那么您就相当于把钱委托给了柜员让他去执行存钱的这个函数.

明白了么?

Delegate

delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类。与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与它的签名相匹配的方法的引用"。它所实现的功能与C/C++中的函数指针十分相似。它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。但与函数指针相比,delegate有许多函数委托和事件在 .Net Framework中的应用非常广泛指针不具备的优点。首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。在引用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。其次,与函数指针相比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法,你无须担心delegate会指向无效地址或者越界地址。

实现一个delegate是很简单的,通过以下3个步骤即可实现一个delegate:

1. 声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。

2. 创建delegate对象,并"将你想要传递的函数作为参数传入"。

3. 在要实现异步调用的地方,通过上一步创建的对象来调用方法。

using System;

public class MyDelegateTest

{

// 步骤1,声明delegate对象

public delegate void MyDelegate(string name);

// 这是我们欲传递的方法,它与MyDelegate具有相同的参数和返回值类型

public static void MyDelegateFunc(string name)

{

Console.WriteLine("Hello, ", name);

}

public static void Main()

{

// 步骤2,创建delegate对象(实例??)

MyDelegate md = new MyDelegate(MyDelegateTest.MyDelegateFunc);

// 步骤3,调用delegate

md("sam1111");

}

}

输出结果是:Hello, sam1111

了解了delegate,下面我们来看看,在C#中对事件是如何处理的。

C#中的事件处理实际上是一种具有特殊签名的delegate,象下面这个样子:

public delegate void MyEventHandler(object sender, MyEventArgs e);

其中的两个参数,sender代表事件发送者,e是事件参数类。MyEventArgs类用来包含与事件相关的数据,所有的事件参数类都必须从System.EventArgs类派生。当然,如果你的事件不含参数,那么可以直接用System.EventArgs类作为参数。

就是这么简单,结合delegate的实现,我们可以将自定义事件的实现归结为以下几步:

1.定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。

2.定义事件参数类,此类应当从System.EventArgs类派生。如果事件不带参数,这一步可以省略。

3.定义"事件处理方法,它应当与delegate对象具有相同的参数和返回值类型"。

4.用event关键字定义事件对象,它同时也是一个delegate对象。

5.用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。

6.在需要触发事件的地方用调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。名字是OnEventName。

7. 在适当的地方调用事件触发方法触发事件。

下面是一个简单的例子:

using System;

public class EventTest

{

// 步骤1,定义delegate对象

public delegate void MyEventHandler(object sender, System.EventArgs e);

// 步骤2(定义事件参数类)省略

public class MyEventCls

{

// 步骤3,定义事件处理方法,它与delegate对象具有相同的参数和返回值类型

public void MyEventFunc(object sender, System.EventArgs e)

{

Console.WriteLine("My event is ok!");

}

}

// 步骤4,用event关键字定义事件对象

private event MyEventHandler myevent;

private MyEventCls myecls;

public EventTest()

{

myecls = new MyEventCls();

// 步骤5,用+=操作符将事件添加到队列中

this.myevent += new MyEventHandler(myecls.MyEventFunc);

}

// 步骤6,以调用delegate的方式写事件触发函数

protected void OnMyEvent(System.EventArgs e)

{

if(myevent != null)

myevent(this, e);

}

public void RaiseEvent()

{

EventArgs e = new EventArgs();

// 步骤7,触发事件

OnMyEvent(e);

}

public static void Main()

{

EventTest et = new EventTest();

Console.Write("Please input ''a'':");

string s = Console.ReadLine();

if(s == "a")

{

et.RaiseEvent();

}

else

{

Console.WriteLine("ERROR");

}

}

}

输出结果如下,红色为用户的输入:

Please input ‘a’: a

My event is ok!

相关阅读

小白PM跟我来:如何搞定APP中的“搜索”功能?

如何搞定APP中的“搜索”功能?本文主要围绕电商这个类别来给大家分析,一起来看看~如果让你独立负责搜索功能,你需要干些什么呢?可能大

ESD控制中的电阻率和电阻广东ACL 380表面电阻率仪

关于电阻率和电阻之间的差异,存在很多混淆。我们会定期向您提问,所以希望这篇文章能够解决任何误解 - 我们将解释两者之间的差异,并

一种好玩的营销策略:随机事件营销玩法

这种随机事件营销玩法,就没让我失望过!一说到促销活动,大多都是优惠打折、借势降价、满减、买一送一、返现、以及砸金蛋、大转盘、抽

【原创】无线破解Aircrack-ng套件详解--airmon-ng与airo

一:Aircrack-ng详解   1.1 Aircrack-ng概述 Aircrack-ng是一款用于破解无线802.11WEP及WPA-PSK加密的工具,该工具在2005年11月之

自如回应阿里员工去世事件:所有的批评收下所有的责任承

A5创业网(公众号:iadmin5)9月2日报道,近日一篇名为《阿里P7员工得白血病身故,生前租了自如甲醛房》的公众号文章引起广泛关注。文章写

分享到:

栏目导航

推荐阅读

热门阅读