0%

C#的委托与事件

委托

可以认为委托是拥有一个或多个方法的对象,这里的对象和面向对象编程中的对象略有区别,正常情况下是不能“执行”一个对象,但是委托与典型的对象不同。可以“执行”委托,此时委托会“执行”它包含的所有方法。

声明委托

声明委托就像是在头文件中声明一个函数头,只不过需要在返回类型前面加上关键词”delegate”

1
2
delegate void MyDel(int a, int b);
MyDel myDelegate;

上面就是声明了一个委托类型MyDel,该委托类型需要传入两个整型参数a、b,并且会返回void,第二行代码创建了myDelegate实例。


接下来做一个简单演示,定义一个委托和一个myClass类,其中包含sumTwoNum方法,将该方法赋给委托,通过委托来进行计算两个数的和;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;

namespace MyDelegate
{
delegate int MyDel();

class Program
{
static void Main(string[] args)
{
myClass m1 = new myClass(1,2);
MyDel myDelegate = new MyDel(m1.sumTwoNum);
Console.WriteLine(myDelegate());

}

}
public class myClass
{
private int num1;
private int num2;
public int sumTwoNum()
{
return num1+num2;
}
public myClass(int a, int b)
{
num1 = a;
num2 = b;
}
}

}

上面的代码中,定义了一个myClass类,其中包含两个私有整型变量num1、num2,及一个sunTwoNum的求和方法;
将myDelegate实例化,并且将m1.sumTwoNum赋给myDelegate委托,这样执行myDelegate()后,就可在控制台输出1+2的结果。

1
2
3
myDelegate += class.method2;
myDelegate += class.method3;
...

上面的代码展示了给myDelegate增加更多的实例方法,通过”+=”赋值,也可以将静态方法赋给委托对象,这样在执行委托时,就会执行其中“拥有”的全部方法。


事件

程序运行时常常会有这样的需求,就是在某个特定事件发生时,程序的其他部分可以得到该事件已经发生的通知,事件就可以满足这种需求。
发布者类定义了一些程序其他类可能感兴趣的事件,其他类就可以注册这些事件,当发布者类的定义事件发生时,已经注册的类就可以获得通知,事件触发后执行的方法称为回调方法,也可以称为事件处理程序。
为什么要将委托和事件一起来介绍,就是因为事件就像是专门用于特殊途径的简单委托。

通过事件传递参数的例子

这个例子中包含一个Args类,该类是用来保存需要从发布者传递到订阅者的信息;当然还需要一个publisher类,publisher中有RunInPub方法,从方法名中就可以看出,这个方法是在publisher的实例中的方法,当publisher的实例运行该方法,就会将Args类的实例信息发送出去;最后还需要一个subscriber类,subscriber类中包含EventForPublisher方法,从该方法的名字可以看出,这个方法是订阅者subscriber在publisher注册的方法。
以下为Args类的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Args : EventArgs
{
private string name;
private int age;
private bool isStupid;

public Args(string theName, int theAge, bool stupidState)
{
name = theName;
age = theAge;
isStupid = stupidState;
}
private string boolToString(bool state)
{
if (state)
{
return "stupid";
}
else
{
return "not stupid";
}
}
public string[] GetArgs()
{
string[] argsArray = new string[3];
argsArray[0] = name;
argsArray[1] = age.ToString();
argsArray[2] = boolToString(isStupid);
return argsArray;
}
}

可以看出Args类是继承于EventArgs类,EventArgs类是专门用来在事件的发布者与订阅者之间传递参数的类,Args类中包含三个字段name、age和isStupid,为了数据安全,三个字段均设为private;一个Args的构造函数,用于初始化Args的实例;一个boolToString方法,用于将bool类型isStupid转化为字符串类型;一个GetArgs()函数,返回包含私有字段的字符转数组。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class publisher
{
public event EventHandler<Args> Event;
Args godricArgs = new Args("godric",30,true);
public publisher(subscriber sub)
{
this.Event += sub.EventForPublisher;
}

public void RunInPub()
{
Event(this, godricArgs);
}
}

以上为publisher类,该类中通过:

1
public event EventHandler<Args> Event;

语句,声明了Event事件,该事件是通过泛型委托EventHandler自定义的类注册的;在publisher的构造函数中,将sub实例的EventForPublisher方法“赋值”给Event事件,意思就是Event事件中现在有了一个方法,这个方法就是EventForPublisher;在RunInPub方法中,通过执行Eevnt(this, godricArgs),将godricArgs中的信息发布出去


1
2
3
4
5
6
7
8
9
public class subscriber
{
public void EventForPublisher(object o, Args args)
{

Console.WriteLine("The name is "+args.GetArgs()[0]+
", the age is "+args.GetArgs()[1]+" and he is "+args.GetArgs()[2]+".");
}
}

以上为subscriber类,该类中只包含有一个EventForPublisher方法,从名字也可以看出,这个方法就是subscriber的实例注册到事件Event中的方法,该方法执行后,会将args传来的数组中的信息显示出来。
以上的代码组合起来,就实现了从publisher类中将godricArgs信息传递出去,并且传递的方法是在subscriber中定义的。
事件运行结果
最后,我努力来打个比方,事件的发布和订阅就好比是,发布者好比是西餐厅,订阅者就好比顾客,西餐厅可以提供各种服务,但是具体是什么服务,需要顾客来”订阅(this.Event += sub.EventForPublisher)”,比如顾客说要一份牛排并且三分熟(void EventForPublisher(object o, Args args)),餐厅就会按要求(void EventForPublisher(object o, Args args))把牛排做好(执行Event(this, godricArgs)),我现在也就只能理解到这个程度了,以后如果有新的想法,在添加吧。