前言:
上篇博文《接口包含内容概述1——接口相关概述及接口中属性的实现》最后留有一疑问:一个接口为什么可以包含一个事件,却不能包含一个委托呢? 在这里要想对这个问题解答,首先必须搞清楚委托和事件这两个容易使人眩晕的问题:
委托概述:
在 C 语言 的众多种类型指针中,有一种叫做“函数指针”,即是指函数的入口地址。在 C# 中委托的概念与其相类似。而与C 语言中函数指针不同的是,.NET 中的委托是类型安全的。
委托的使用:
同使用一个类相类似,首先定义要使用的委托,这里规定了委托所代表的哪种类型的方法; 其次创建该委托的一个或多个实例。这里举一示范代码:
// CopyRight: http://www.cnblogs.com/yangmingming
// Notes: 为简便,将委托的定义,和验证代码放于一起
namespace DelegateDemo
{
class Program
{
// 委托的定义,制定对应方法的类型
public delegate int DelegateShowInt( int i);
public static int ShowData( int i)
{
return i + 1 ;
}
static void Main( string [] args)
{
DelegateShowInt showInt = new DelegateShowInt(ShowData);
Console.WriteLine( " The Result is {0} " , showInt( 1 ));
}
}
}
最后调试结果为:
上例可见一般情况下,委托的应用,即在对应一个方法使用委托的情况下。
注意:
对于式:DelegateShowInt showInt = new DelegateShowInt(ShowData) 可以认为是所有委托都有的“构造函数”形式——其参数是函数引用。
多播委托:
前面例子中是最为简单、常用的一种形式(一个委托实例,调用一个方法)。因为我们可以实例化一个或多个某种委托的实例,另一方面,我们也可以让一个委托调用多个方法,这里称作多播委托。
// CopyRight: http://www.cnblogs.com/yangmingming
// Notes: 为简便,将委托的定义,和验证代码放于一起
namespace DelegateDemo
{
class Program
{
// 定义委托,注意返回类型为 :void
public delegate void DelegateShowInt( int i);
public static void ShowData( int i)
{
Console.WriteLine( " ShowData is {0} " , i);
}
public static void ShowData2( int i)
{
Console.WriteLine ( " ShowData2 is {0} " ,i + 1 );
}
static void Main( string [] args)
{
// 多播委托的使用方法:+=
DelegateShowInt showInt = new DelegateShowInt(ShowData);
showInt += new DelegateShowInt( ShowData2);
showInt( 1 );
showInt( 2 );
}
}
}
而对应的调试结果为:
通过实例,可见我们对委托对象,实现了多个方法的绑定。
注意: 之所以要求多播委托的返回类型为void,是因为如果有返回值,将没有意义,起到作用的只有最后一个被调用的函数而已!
事件概述:
有了前述对委托的讲述,为这里讲解事件做好了铺垫。事件,其在Windows Form中得到极大应用,这里举一最常见的点击按钮,触发事件的例子。
2 {
3 this .buttonOne = new System.Windows.Forms.Button();
4 this .SuspendLayout();
5 //
6 // buttonOne
7 //
8 this .buttonOne.Location = new System.Drawing.Point( 241 , 37 );
9 this .buttonOne.Name = " buttonOne " ;
10 this .buttonOne.Size = new System.Drawing.Size( 75 , 23 );
11 this .buttonOne.TabIndex = 0 ;
12 this .buttonOne.Text = " button " ;
13 this .buttonOne.UseVisualStyleBackColor = true ;
14 this .buttonOne.Click += new System.EventHandler( this .button_Click);
15 //
16 // Form1
17 //
18 this .AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
19 this .AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
20 this .ClientSize = new System.Drawing.Size( 292 , 266 );
21 this .Controls.Add( this .buttonOne);
22 this .Name = " Form1 " ;
23 this .Text = " Form1 " ;
24 this .ResumeLayout( false );
25
26 }
可见在14行,对对象buttonOne的事件Click赋予了委托,该委托指定了形式:
{
}
对应类型的参数含有object和EventArgs,并且返回为void形式。这样事件就与委托相联系上。
同样可以实现不同对象的事件,对应同一委托情形:
this .buttonTwo.Click += new System.EventHandler( this .button_Click);
综上可见:
1.委托,作为一种特殊的类型,雷同于定义一个类(实际上,后台即是将其作为类处理) ;
2.事件,规范了其类型(委托类型);
综上之,之所以接口不能包含委托,而接口为什么可以包含事件呢?
因为委托是一种与类同等地位的特殊类型(类的实例是存储数据的托管内存空间,而委托则只有方法地址而已),故接口不能包含委托;事件从地位上不与类、接口同一层次,事件的独特机制使得事件可以是一个接口的标准组成部分,只要继承的类包含一个public事件成员;(看样要想说明白,还要将事件讲述更清楚些,呵呵~)
附:附加版
如上文所述,事件一般都是应用在诸如Windows form这样的事件驱动环境中。具体例子可见上述按钮触发事件自动生成的代码。然而对事件而言,我们自己也可以定义事件的,见下例:
2
3 // CopyRight: http://www.cnblogs.com/yangmingming
4
5 // Notes: 为简便,将自定义事件的定义,和验证代码放于一起
6
7
8 namespace SelfDefinitionEvent
9 {
10 // 先定义一委托类型
11 public delegate void DelegateDog( );
12
13
14 public class Dog
15 {
16 // 定义事件类型,其类型对应于自定义委托类型
17 public event DelegateDog EventDog;
18 private string name;
19 public string Name
20 {
21 get { return name; }
22 set { name = value; }
23 }
24 public void Invoked()
25 {
26 // 使用事件方法:像使用其对应方法一样使用
27 EventDog();
28 }
29 }
30 class Program
31 {
32 public static void Response()
33 {
34 Console.WriteLine( " It will attack human. " );
35 }
36 static void Main( string [] args)
37 {
38 Dog dog = new Dog();
39 dog.Name = " Jack " ;
40 // 对事件的操作,使之与对应委托相关
41 dog.EventDog += new DelegateDog(Response);
42 dog.Invoked();
43
44 }
45 }
46 }
47
最后结果为:
从上例,可以看到自定义事件的从定义、赋值、使用等个部分的方法,也可以加深对事件的了解。