63

Delegate和Event有什么区别?-腾讯游戏学院

 5 years ago
source link: http://gad.qq.com/article/detail/287840
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
把学到的东西记在自己的私人笔记中很方便,如果将他们分享出来,就不得不想着怎么排版会好一些,某些句子有没有更合适的描述,甚至是内容有误怎么办? 如果是这样的话,占用的时间和精力就太多了,反而会让分享变成一种负担。所以,有时间的情况下,就写得详细一些,没时间就以分享我的随笔为主。

文中有误的地方,还希望大家能够指正,更欢迎补充~


Delegate和Event有什么区别?

Delegate是引用类型,会在CLR拖管堆中分配内存,是一个包含了相同返回值和函数签名的方法列表,这个列表叫Invocation List,如果Deletate中只包含一个方法,他就像C++中的函数指针。

Delegate重载了+=,-= ,=操作符,可以非常方便的将方法绑定到Delegate上,通常用于异步回回调处理,通知等等操作。

对于绑定到Delegate上的方法,引用类型支持协变和逆变。

协变:针对返回类型,可以是Delegate返回类型派生的一个类型。
逆变:针对方法参数,可以是Delegate参数类型的基类。

比如我声明如下Delegate:

public delegate object MyCallBack(System.IO.FileStream stream);
返回类型object,参数类型为FileStream

我定义下面这个方法:
public string GetInfo1(System.IO.Stream io)
	{
		return "";
	}
那么我可以成功的将GetInfo1绑定到MyCallBack上,因为string是object的派生类,满足协变,
System.IO.Stream是System.IO.FileStream的基类。满足逆变。

如果我将System.IO.Stream改为System.IO.BufferedStream就不行了,因为他不是FileStream的基类。

Delegate分为两种类型:
Single Delegate:仅指向一个方法,上面有提到,只有一个方法的时候就像C++中的函数指针。
Multicast Delegate:可以指向多个方法,指向了一个Delegate[]的数组,InvocationList。

这样就会造成一种情况:
myCallBack+=...
myCallBack+=...
myCallBack=....
如果不小心书写错误,最后一行将+=写成了=,将就会上面已经添加到InvocationList中的Delegate全部清掉,指向Single Delegate。

所以在使用的过程中,一定要注意。

还有一点,Delegate是引用类型,他不能声明在Interface中,但是这两个问题在Event事件中都得到了解决。

Event是在Delegate的基础之上进行了封装,并且明确了应用场景。在Event的内部会隐式的生成一个私有的Delegate,我们只能通过+=,-=的方式来绑定方法到私有委托上,无法在外部通过=操作符对Delegate进行操作,保护了Delegate不会被意外的修改。并且这样做也是合理的,面向对象封装的特性,Event对Delegate进行了封装,只对外提供必要的接口。

对于明确了应用场景方面,首先,我们在开发中总会有这样的需求,当一个对象发生改变的时候,其它某些对象要求能够收到通知,并做出响应,比如我们订阅微信里的公众号,当有新文章发布以后,会推送给每个订阅的人。在游戏中的应用就更加的普遍了。

这其实就是典型的观察者模式,发布者/订阅者,由发布者定义了一些其它对象可能会"感兴趣"的事件,由订阅者来注册,当事件发生时,由发布者来通知事件的所有观察者们。

为了验证Event中定义了一个私有Delegate的说法,我们可以看下IL代码:

5bcc50ce2fb93.png

	public event System.Action<int, int> testEventA;
	public event System.EventHandler testEventB;

这是在代码中定义的两个事件testEventA,testEventB,通过上面的IL结构图,可以清晰的看到他生成了两个私有的Delegate以及add_xxxx,remove_xxxx公开方法。

事件不是引用类型,他与方法和属性一样,都是成员,这就意味着,事件是可以声明在Interface中的,这样非常便于面向对象开发,而Delegate是引用类型,是无法声明在Interface中的。

另外,在C#的语言内部,提供了很多无返回值的Delegate定义,从无参到多参,还有带返回值的Delegate,从无参到多参的定义,分别是:

System.Func
System.Action

如果提供的这些就能满足使用要求,就没有必要自己定义Delegate。


综上所述,我个人认为,Delegate通常用于做一些异步回调处理,通知等等,但实际上,这些操作我们都可以看作成Event事件,而且Event的内部实现通知的部分就是Delegate,可以说Event的核心就是Delegate,所以,使用Event的两点好处:

1.Event包含了一个Delegate,并且是私有的,对Delegate起到了保护作用,比如我们无法使用=操作来重置Delegate。
2.我们可以在接口中声明Event,这样更便于面向对象的开发,符合面向接口编程。

所以在以后的使用过程中,尽量的使用Event吧。

文中有误的地方,还希望大家能够指正,更欢迎补充~

更多细节的部分可以参考下面stackoverflow中的讨论:

https://stackoverflow.com/questions/29155/what-are-the-differences-between-delegates-and-events
http://www.unitygeek.com/delegates-events-unity/






About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK