基本委托

委托

 定义委托的语法和定义方法比较相似,只是比方法多了一个关键字delegate ,我们都知道方法就是将类型参数化,所谓的类型参数化就是说该方法接受一个参数,而该参数是某种类型的参数,比如int、string等等;而委托是将方 法参数化,说了上面的那个类型参数化之后,相信你也能猜到方法参数化的意思了,对,就是将方法作为一个参数传到一个委托中。

首先来看看声明委托的语句:

public deletate void MyDelegate();  

public:访问修饰符  delegate:关键字  void:返回类型  MyDelegate:委托名称  ( )参数列表  

 

看到声明大家会想了,为什么该委托的返回值,参数列表要这样的,我不能返回一个 string,一个int么?我不能给委托加几个参数么? 答案是:当然可以,但委托的定义是相对于方法来说的,因为得你的委托最终是要来注册方法的,而你的方法是具有某种签名的,所以你要给怎样签名的方法来声明 一个委托,该委托就要和该方法具有同等的签名,就类似于你用一个int 类型的变量去接受一个string类型的值,显然是不行的(个人理解).... 

 委托只要定义就可以了,我们并不需要关心他的实现  

 委托概述

步骤

1.声明委托(类型) delegate void MyDel(int value)

2.声明 委托类型的变量 MyDel my;

3.创建委托的事例并且把的引用赋值给变量,然后增加到第一个方法(与类不同的地方)

 del=new MyDel(SClass.OtherM2);

void OtherM2(int value)

{

Console.WriteLine("ssss");

}

4.调用委托对象

del(3);

编译时

委托类型

void MyDel(int x)

运行时

内存-----》void MyDel(int x)

            调用列表SClass.OtherM2

------------------------------------------------------------------------------------------------------------------------------------

使用匿名方法

delegate int OtherDel(int InParam);

SomeDel mDel=delegate(int y){ 语法块; };

if(null !=mDel)

mDel(3);

Lambda 表达式

MyDel del=delegate(int x){ return x+1; };//匿名方法

MyDel del=(int x)=>{ return x+1; };//Lambda 表达式

MyDel del=x=>return x+1;//Lambda 表达式

-----------------------------------------------------------------------------------------------------------------------------------

事件的工作方式

 

事件是根据发布者或预订者模型设计的。

触发事件的类称为发布者。

想要对事件作出响

应的类将一个或多个方法添加到发布者的委托中。该类称为预订者。当发布者调用委托时,

也会调用预订者的方法。

通过使用委托,

发布者可以调用预订者中的一个或多个方法,

而无

需了解方法的详细信息。

预订者也可以指定零个、

一个或多个方法来响应发布者的事件,

无需了解事件的详细信息。

大多数时间,

事件都会被预订者忽略,

并而且不会有与事件关联

的方法。

 

预订者要了解的惟一内容就是发布者事件委托的参数签名。

从本质上来说,

事件都是单

向的,它们不具有返回值;因此预订者不必考虑事件的返回值签名。

 

在程序中创建并使用自定义事件包含三个步骤。

 

 

首先,必须在类中声明事件并确定将要使用的委托和参数。

 

 

其次,必须定义在触发事件时要调用的委托。

 

 

最后,必须设计事件参数类,该参数类的实例会将信息传递给被调用的方法。如果

使用内置的

 

EventArgs 

对象和

 

EventHandler 

委托,则可以不执行最后两个步骤。

事件的工作方式  事件是根据发布者或预订者模型设计的。
触发事件的类称为 发布者。想要对事件作出响应的类将一个或多个方法添加到发布者的委托中。该类称为 预订者
当发布者调用委托时,也会调用预订者的方法 。通过使用委托,发布者可以调用预订者中的一个或多个方法,而无需了解方法的详细信息。 预订者也可以指定零个、一个或多个方法来响应发布者的事件 ,而无需了解事件的详细信息。大多数时间,事件都会被预订者忽略,并而且不会有与事件关联的方法。  预订者要了解的惟一内容就是发布者事件委托的参数签名。从本质上来说,事件都是单向的,它们不具有返回值;因此预订者不必考虑事件的返回值签名。  在程序中创建并使用自定义事件包含三个步骤。  
 首先,必须在类中声明事件并确定将要使用的委托和参数。 
 其次,必须定义在触发事件时要调用的委托。 
  最后,必须设计事件参数类,该参数类的实例会将信息传递给被调用的方法。如果 使用内置的 EventArgs 对象和 EventHandler 委托,则可以不执行最后两个步骤。

-----------------------------------------------------------------------------------------------------------------------------------

委托的使用

注册委托有两种方法:

第一种直接将方法赋值[=]或者用“+=” 给一个委托==>委托名 =[+=]  方法名 

第二种委托本质也是一个类,只是一个特殊的类,所以我们也可以实例化一个委托对象通过委托构造函数来注册委托==》委托名 对象名= new 委托名(方法名) 

 

 了解了委托的声明和使用,我们就可以来看小例子来加深理解了

 首先看看界面: 

 

界面上就是简单的四个按钮 两个属于委托,两个属于事件,都是一个用来执行,一个用来干扰,以便于来理解委托事件

然后看后台代码,首先我定义了一个Test类,声明委托,实例了委托,还声明了事件,写了个方法用来触发事件,代码如下: 

复制代码
  1      public  class Test
  2     {
  3          // 声明一个委托
  4          public  delegate  void MyDelegate();
  5 
  6          // 创建一个委托实例
  7          public MyDelegate myDel;
  8          // 声明一个事件
  9          public  event MyDelegate EventMyDel;
10 
11          // 事件触发机制(必须和事件在同一个类中) 外界无法直接用EventMyDel()来触发事件
12          public  void DoEventMyDel()
13         {
14             EventMyDel();            
15         }    
16     }
复制代码

然后为了方便测试,我还定义了三个方法在Form1类,代码如下:

复制代码
  1          // 方法A
  2          public  void Fun_A()
  3         {
  4             MessageBox.Show( " A 方法触发了 ");
  5         }
  6 
  7          // 方法B
  8          public  void Fun_B()
  9         {
10             MessageBox.Show( " B 方法触发了 ");
11         }
12          // 方法C
13          public  void Fun_C()
14         {
15             MessageBox.Show( " C 方法触发了 ");
16         }
复制代码

然后在页面Page_Load时注册委托,将方法A方法B挂载到委托链上,代码如下:

复制代码
  1         // 页面载入事件
  2          private  void Form1_Load( object sender, EventArgs e)
  3         {
  4             
  5             // 注册委托(挂载方法)
  6            test.myDel += Fun_A;
  7            test.myDel += Fun_B;
  8 
  9             // 注册事件(挂载方法)
10             // test.EventMyDel += Fun_A;
11             // test.EventMyDel += Fun_B;
12         }
复制代码

然后给[执行委托]按钮添加Click事件,代码如下:

复制代码
1         // 执行委托
2          private  void button1_Click( object sender, EventArgs e)
3         {
4              // 执行委托链中的方法
5             test.myDel();
6         }
复制代码

显示效果:

   

说明没问题,方法都挂载到委托链上了,但是如果这时候我们来进行下干扰呢?各位想想看,结果会是怎么样了呢,先贴上干扰的代码:
复制代码
1        // 委托干扰事件
2          private  void button2_Click( object sender, EventArgs e)
3         {
4              // 给委托赋 null 值
5             test.myDel =  null;
6 
7              // 给委托挂载上C方法
8             test.myDel += Fun_C;
9       
复制代码
其实这里的所谓的“干扰”,就是给以存在的委托链中附加了一个  null  的对象,然后在给委托附加 C方法 ,此时按如下步骤运行程序:

 

看看结果会怎么样,哎,发现就只有C方法被触发了:

大家想想,为什么会这样呢??为什么A,B方法不执行了呢??这是因为原来的委托链 是已经挂载了A,B两个方法了,但这时突然被干扰了下,又附加了一个null对象,破坏了原有的委托链了,但这又说明了什么呢?因为委托本质就是一个类, 它包含一对有用的字段,第一个字段是存放该对象的引用,第二个字段存放一个方法的指针,所以我们可以把委托理解成一个指向函数的指针,当一个方法作为参数 赋值给一个委托的时候,该委托就指向了该方法的首地址,即方法名,所以当我们给委托注册A,B两个方法,该委托就同时指向了A,B两个方法的首地址,但这 是又突然给委托赋值了,且赋值了一个null对象,注意这里用的是赋值符号[=],这就是说让该委托清除原有的指针指向,此时指向一个null,之后又给 委托注册了C方法,所以此时委托即指向null,又指向了C方法的首地址,这就是为什么运行时只会看到C方法被触发的原因了!

那就是说现在的委托变得不安全了,哪天一个项目中给委托注册了很多方法,但突然被干扰了下,前面的注册都失效了,那我们前面做的工作不是白做了,那有没有办法可以防止这种干扰呢??答案是当然有,相信聪明的你也应该猜到了,这时就是事件该上场的时候了。

 

事件

事件就是一个特殊的委托,委托和事件就类似于字段和属性的关系,事件是对委托做了一个封装(这是个人理解)

先看看声明一个事件:

public Event MyDelegate EventMyDel;

public:访问修饰符  Event:关键字 MyDelegate:委托 EventMyDel:事件名称

 

接下来让我们来看看我们用反编译工具来反编译下该项目的exe可执行文件,看看当我们给事件注册上方法时,事件内部在做什么,附上反编译代码:

从 反编译中就可以充分看出,事件的本质就是一个委托,它的内部仍然是用一个委托,该委托的名称的方法就只有和事件名首字母的大小写不同而已,该委托来负责接 收事件,然后通过addremove方法来实现委托的注册和删除,即当我们给委托注册一个方法时,内部就调用add方法,通过 Delegate.Combine()方法来实现将方法附加到委托链上,当我们删除委托链上的一个方法时,即内部调用remove方法,通过 Delegate.Remove()方法,将该方法从委托链上移除,所以通过反编译工具,我们就可以清楚的知道事件内部的实现代码了。

接下来看看事件的效果,首先在Page_Load事件中注册事件,我们将A,B方法注册到事件上,代码如下:

复制代码
  1         // 页面载入事件
  2          private  void Form1_Load( object sender, EventArgs e)
  3         {
  4             
  5             /// /注册委托(挂载事件)
  6             // test.myDel += Fun_A;
  7             // test.myDel += Fun_B;
  8 
  9             // 注册事件
10             test.EventMyDel += Fun_A;
11             test.EventMyDel += Fun_B;
12         }
复制代码
然后我们点击 [执行事件]按钮.贴上代码:
复制代码
1         // 执行事件
2          private  void button3_Click( object sender, EventArgs e)
3         {
4              // 执行事件触发方法
5             test.DoEventMyDel();
6         }
复制代码

看看效果,如图:

 

和刚开始的委托一样,没有问题,两个方法都触发了,接下来再让我们来实施干扰,附上干扰代码:
事件干扰

慢着,,此时编译报错了,报了什么错呢,,我们看看:

说明了什么,,说明我们没法对事件用赋值[=]号来进行注册,这就避免了破坏直接委托链的指针指向了,,但你会想了,那如果我们用附加[+=]上一个null对象呢?会干扰到么??好的,,我们实施下,修改代码,如下:

修改干扰事件

运行如图:

 

运行结果如下:

 

所以没有问题,即使你附加了一个 null 对象,三个方法照样依次执行了,,这就是事件的封装效果了.......

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值