C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx

上传人:b****7 文档编号:22760011 上传时间:2023-02-05 格式:DOCX 页数:14 大小:33.82KB
下载 相关 举报
C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx_第1页
第1页 / 共14页
C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx_第2页
第2页 / 共14页
C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx_第3页
第3页 / 共14页
C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx_第4页
第4页 / 共14页
C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx

《C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx(14页珍藏版)》请在冰豆网上搜索。

C#中的委托Delegate和事件Event例子解释Word格式文档下载.docx

nowcallmax("

a<

"

b<

)..."

endl;

a>

b?

a:

b;

t<

}

min(int 

nowcallmin("

typedef 

(*myFun)(int 

b);

//定义一个函数指针用来引用max,min

//回调函数

callback(myFunfun, 

fun(a,b);

main()

10;

55;

callback(max,i,j);

callback(min,i,j);

Output:

nowcallmax(10,55)...

55

nowcallmin(10,55)...

10

Pressanykeytocontinue

输出的结果有可能另一些对函数指针不熟悉的朋友我些意外,我们并没在main()中显式调用max(),min()呀,怎么会调用到它们呢。

再仔细检查一下:

你可能发现了:

callback(max,i,j);

这个函数调用了max(),这下好了。

你便可以回答类似于这样的问题:

我怎么在一个函数(callback)体内调用[主调用函数中的函数(max或min)],最好能通过参数指入具体需要指定哪一个函数?

这便是函数指针的作用了,通过转入函数指针,可以很方便的回调(callback)另外一些函数,而且可以实现参观化具体需要回调用的函数。

2,Introducedelegateinc#;

.net里一向是"

忌讳"

提及"

指针"

的,"

很多程度上意味着不安全。

C#.net里便提出了一个新的术语:

委托(delegate)来实现类似函数指针的功能。

我们来看看在C#中怎么样实现上面的例子。

WinXP+C#invs2003

System;

Class1

class 

ExcelProgram

static 

Console.WriteLine("

nowcallmax({0},{1})"

a,b);

Console.WriteLine(t);

nowcallmin({0},{1})"

delegate 

myFun(int 

//定义一个委托用来引用max,min

[STAThread]

Main(string[] 

args)

callback(new 

myFun(max),i,j);

myFun(min),i,j);

Console.ReadLine();

其实代码上大同小异,除了几个static申明以外(C#除静态成员外必须要求对象引用),最大的变化要算定义"

函数指指"

,哦...不..不..不..应该是定义"

委托"

(小样穿上马甲了..).定义委托的语法如下:

delegatevoid 

myFun(inta,intb);

其中delegate是关键字,myFun是委托名,剩下的是函数签名(signature).我们可以申明一个委托:

myFunMax=newmyFun(max);

那么上面的回调函数的代码便可以写成:

callback(Max,i,j);

3,Differencebetweenfunctionpointeranddelegate;

委托除了可以引用一个函数外,能力上还有了一些加强,其中有一点不得不提的是:

多点委托(Multicastdelegate).简单地讲就是可以通过一个申明一个委托,来调用多个函数,不信?

我们只要稍微更改一下上面的C#代码中的Main函数就可以了,类似:

staticvoidMain(string[]args)

inti=10;

intj=55;

myFunmulCast=newmyFun(max);

mulCast 

+= 

newmyFun(min);

//

(1)

callback(mulCast,i,j);

//callback(newmyFun(min),i,j);

输出如下:

没骗你吧,我们只用了一个委托mulCast便同时调用了max和min。

不知你注意到没有,上面代码的

(1)处用"

+="

给已经存在的委托(mulCast)又加了一个函数(min)。

这样看来C#中的委托更像一个函数指针链表。

实质是在C#中,delegate关键字指定的委托自动从System.MulticastDelegate派生.而System.MulticastDelegate是一个带有链接的委托列表,在callback中只需调用mulCast的引用便可以以同样的参数调用该链表中的所有函数。

如果还是觉得不过隐,那我们就继续,下图展示了刚才那段C#代码的IL(用ILDasm反汇编即可):

在C#中委托是作为一个特殊的类型(Type,Object)来对待的,委托对象也有自己的成员:

BeginInvoke,EndInvoke,Invoke。

这几个成员是你定义一个委托时编译器帮你自动自成的,而且他们都是virtual函数,具体函数体由runtime来实现。

我们双击一个callback,可以看见以下IL:

//代码大小 

9(0x9)

.maxstack 

8

IL_0000:

ldarg.0

IL_0001:

ldarg.1

IL_0002:

ldarg.2

IL_0003:

callvirt 

instancevoidClass1.ExcelProgram/myFun:

:

Invoke(int32,

int32)

IL_0008:

ret

}//endofmethodExcelProgram:

callback

从这段IL我们可以看出,当我们使用语句:

fun(a,b)时,调用的却是委托对象(即然委托是类型,那么他自也就会有对象)的myFun:

Invoke().该委托对象(即上面的mulCast)通过调用Invoke来调用对象本身所关系的函数引用。

那我们再看看,一个委托对象是怎么样关联到函数的呢,我们双击Main函数,可以看到以下IL,虽然IL语法复杂但仍不影响我们了解它是怎么样将一个委托关联到一个(或多个)函数的引用的。

.methodprivatehidebysigstaticvoid 

Main(string[]args)cilmanaged

.entrypoint

.custominstancevoid[mscorlib]System.STAThreadAttribute:

.ctor()=(01000000) 

58(0x3a)

4

.locals([0]int32i,

[1]int32j,

[2] 

classClass1.ExcelProgram/myFun 

mulCast)

ldc.i4.s 

10

stloc.0

55

IL_0005:

stloc.1

IL_0006:

ldnull

IL_0007:

ldftn 

voidClass1.ExcelProgram:

max(int32,

IL_000d:

newobj 

.ctor(object,

nativeint)

IL_0012:

stloc.2

IL_0013:

ldloc.2

IL_0014:

IL_0015:

min(int32,

IL_001b:

IL_0020:

call 

class[mscorlib]System.Delegate[mscorlib]System.Delegate:

Combine(class[mscorlib]System.Delegate,

class[mscorlib]System.Delegate)

IL_0025:

castclass 

Class1.ExcelProgram/myFun

IL_002a:

stloc.2

IL_002b:

IL_002c:

ldloc.0

IL_002d:

ldloc.1

IL_002e:

callback(classClass1.ExcelProgram/myFun,

int32,

IL_0033:

string[mscorlib]System.Console:

ReadLine()

IL_0038:

pop

IL_0039:

Main

从上面的IL可以看出对于语句:

myFunmulCast=newmyFun(max);

是通过以max作为参数构建一个委托对象mulCast。

但对于语句:

mulCast+=newmyFun(min);

等价于(你甚至可以用下面的语句代码上面的:

mulCast+=newmyFun(min)):

mulCast=(myFun)Delegate.Combine(mulCast,newmyFun(min));

哦,原来是通过调用Delegate.Combine的静态方法将mulCast和min函数进行关联,Delegate.Combine方法只是简单地将min函数的引用加至委托对象mulCast的函数引用列表中。

4,Introduceevent;

事件/消息机制是Windows的核心,其实提供事件功能的却是函数指针,你信么?

接下来我们再看看C#事件(Event).在C#中事件是一类特殊的委托.

一个类提供了"

事件"

,那么他至少提供了以下字段/方法:

一个委托类型的字段(field),用来保存一旦事件时通知哪些对象。

即通知所有订阅该事件的对象.别忘记C#中委托是支持多播的。

两个方法,以委托类型为参数。

作用是将订阅该事件的对象方法加至上面的委托类型字段中,以便事件发生后可以通过调用该方法来通知对象事件已发生。

我们简单地定义一个类Test,该类支持事件:

classTest

publiceventEventHandlerOnClick;

publicvoidGenEvent(EventArgse) 

//引发事件方法

EventHandlertemp=OnClick;

//通知所有已订阅事件的对象

if(temp!

=null)

temp(this,e);

我们反汇编这段代码,如下图:

简单地定义一个字段哪来的那么多方法?

其实这都是编译器帮你加上去的。

当你定义一个事件时,编译器为了实现事件的功能会自动加上两个方法来提供“订阅”和“取消订阅”的功能。

通过下面的语法,你便可以订阅事件:

test.OnClick+=newEventHandler(test_OnClick);

也就是说,一旦test事件发生时(通过调用test.GenEvent()方法)。

test便会调用注册到OnClick上的方法。

来通知所有订阅该事件的对象。

订阅是什么?

“订阅就是调用定义事件时自动生成的add_OnClick.”“那取消订阅就是调用定义事件时自动生成的remove_OnClick”,恭喜你!

都学会抢答了.对于上面的订阅事件语句,逻辑意义上等同于:

test.add_OnClick(newEventHandler(test_OnClick));

但C#并不能直接调用该方法,只能通过"

来实现。

来看IL:

IL_003b:

test_OnClick(object,

class[mscorlib]System.EventArgs) 

//先将test_OnClick压栈

IL_0041:

instancevoid[mscorlib]System.EventHandler:

nativeint) 

//new一个委托对对象

IL_0046:

callvirt 

instancevoidClass1.ExcelProgram/Test:

add_OnClick(class[mscorlib]System.EventHandler) 

//通过调用add_OnClick方法将上面生委托加至test的事件(委托列表)中.

5,summarize.

如果对设计模式中的观察者模式较为熟悉的话。

其实支持事件的类也就是观察者模式中的Subject(主题,我个人比较喜欢这么译).而所有订阅事件的对象构成了Observers.

最后来句总结吧,总结也许不严谨,但提供理解那还是绝佳滴..我骗你..(鼻子又变长了).....

"

是"

函数指针"

链表,当然该链表也可以只有一个元素,如果这样的话:

约等于 

;

是一类特特殊的"

,你定义一个"

表示你同时定义了:

一个委托+两个方法。

后记:

如果还不理解事件,先不要急,说不定你先把它忘记不想,等会一闪光,你就会理解了。

或者你等着我下一篇《设计模式----观察者(Observer)》,我想等你看完设计模式中的观察者之后再回来看"

,看"

多播委托(MulticastDelegate)"

应该可以:

忽然开朗。

如果还觉得不过隐。

下面给出一个很好的帮助理解的例子,来自JeffreyRichter.希望我的注解能帮上些忙:

System.Text;

System.Data;

//定义事件引发时,需要传的参数

NewMailEventArgs:

EventArgs

private 

readonly 

string 

m_from;

m_to;

m_subject;

public 

NewMailEventArgs(string 

from, 

to, 

subject)

m_from 

from;

m_to 

to;

m_subject 

subject;

From

get{return 

To

Subject

//事件所用的委托(链表)

NewMailEventHandler(object 

sender, 

NewMailEventArgse);

//提供事件的类

MailManager

event 

NewMailEventHandlerNewMail;

//通知已订阅事件的对象

protected 

virtual 

OnNewMail(NewMailEventArgse)

NewMailEventHandlertemp 

NewMail;

//MulticastDelegate一个委托链表

if(temp 

!

null)

//通过事件NewMail(一种特殊的委托)逐一回调客户端的方法

//提供一个方法,引发事件

SimulateNewMail(string 

NewMailEventA

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1