您的位置:首页 > 其它

事件处理程序的处理顺序问题

2010-03-13 19:15 423 查看
这也是今天讨论到的一个话题,其实还是比较简单的。因为事件处理程序都是在主线程被执行的,所以主线程肯定是依次执行他们。那么究竟是什么决定了这个顺序呢?

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Reflection;

usingSystem.Threading;
namespaceConsoleApplication1
{
classProgram
{
staticvoidMain(string[]args)
{
///这个例子解释了如果为一个事件绑定了多个事件处理程序,那么他们处理的顺序与绑定顺序是一致的

Console.WriteLine("主线程号是:{0}",Thread.CurrentThread.ManagedThreadId);

Employeee=newEmployee();
e.NameChanged+=newEventHandler(e_NameChanged);
e.NameChanged+=newEventHandler(e_NameChanged2);
e.Name="areschen";

Console.Read();
}

staticvoide_NameChanged2(objectsender,EventArgse)
{

Console.WriteLine("第2个事件处理程序触发的时间是:{0}",DateTime.Now);
Console.WriteLine("当前线程号是:{0}",Thread.CurrentThread.ManagedThreadId);
}

staticvoide_NameChanged(objectsender,EventArgse)
{
Console.WriteLine("第1个事件处理程序触发的时间是:{0}",DateTime.Now);
Console.WriteLine("当前线程号是:{0}",Thread.CurrentThread.ManagedThreadId);
}
}

classEmployee
{
publiceventEventHandlerNameChanged;

privatestringname;
publicstringName
{
get
{
returnname;
}
set
{
name=value;
if(NameChanged!=null)
NameChanged(this,null);
}
}
}
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}





其实要深入看的话,这是因为事件的处理程序是通过一个列表来管理的,就是EventHandlerList

[HostProtection(SecurityAction.LinkDemand,SharedState=true)]
publicsealedclassEventHandlerList:IDisposable
{
//Fields
privateListEntryhead;
privateComponentparent;

//Methods
publicEventHandlerList()
{
}

internalEventHandlerList(Componentparent)
{
this.parent=parent;
}

publicvoidAddHandler(objectkey,Delegatevalue)
{
ListEntryentry=this.Find(key);
if(entry!=null)
{
entry.handler=Delegate.Combine(entry.handler,value);//这里的关键在于Delegate.Combine,所以根据注册顺序不一样,是一个顺序型的组合
}
else
{
this.head=newListEntry(key,value,this.head);
}
}

publicvoidAddHandlers(EventHandlerListlistToAddFrom)
{
for(ListEntryentry=listToAddFrom.head;entry!=null;entry=entry.next)
{
this.AddHandler(entry.key,entry.handler);
}
}

publicvoidDispose()
{
this.head=null;
}

privateListEntryFind(objectkey)
{
ListEntryhead=this.head;
while(head!=null)
{
if(head.key==key)
{
returnhead;
}
head=head.next;
}
returnhead;
}

publicvoidRemoveHandler(objectkey,Delegatevalue)
{
ListEntryentry=this.Find(key);
if(entry!=null)
{
entry.handler=Delegate.Remove(entry.handler,value);
}
}

//Properties
publicDelegatethis[objectkey]
{
get
{
ListEntryentry=null;
if((this.parent==null)||this.parent.CanRaiseEventsInternal)
{
entry=this.Find(key);
}
if(entry!=null)
{
returnentry.handler;
}
returnnull;
}
set
{
ListEntryentry=this.Find(key);
if(entry!=null)
{
entry.handler=value;
}
else
{
this.head=newListEntry(key,value,this.head);
}
}
}

//NestedTypes
privatesealedclassListEntry
{
//Fields
internalDelegatehandler;
internalobjectkey;
internalEventHandlerList.ListEntrynext;

//Methods
publicListEntry(objectkey,Delegatehandler,EventHandlerList.ListEntrynext)
{
this.next=next;
this.key=key;
this.handler=handler;
}
}
}

所以,既然是通过线性表来保存的,那么就有一个先后顺序的情况。其实,一个更好的写法是下面这样的
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Reflection;

usingSystem.Threading;
usingSystem.ComponentModel;
namespaceConsoleApplication1
{
classProgram
{
staticvoidMain(string[]args)
{
///这个例子解释了如果为一个事件绑定了多个事件处理程序,那么他们处理的顺序与绑定顺序是一致的

Console.WriteLine("主线程号是:{0}",Thread.CurrentThread.ManagedThreadId);

Employeee=newEmployee();
e.NameChanged+=newEventHandler(e_NameChanged);
e.NameChanged+=newEventHandler(e_NameChanged2);

e.Name="areschen";

Console.Read();
}

staticvoide_NameChanged2(objectsender,EventArgse)
{

Console.WriteLine("第2个事件处理程序触发的时间是:{0}",DateTime.Now);
Console.WriteLine("当前线程号是:{0}",Thread.CurrentThread.ManagedThreadId);
}

staticvoide_NameChanged(objectsender,EventArgse)
{
Console.WriteLine("第1个事件处理程序触发的时间是:{0}",DateTime.Now);
Console.WriteLine("当前线程号是:{0}",Thread.CurrentThread.ManagedThreadId);
}
}

classEmployee
{
//publiceventEventHandlerNameChanged;

protectedEventHandlerListlistEventDelegates=newEventHandlerList();
privateobjectNameChangedEventKey=newobject();

publiceventEventHandlerNameChanged{
add{
listEventDelegates.AddHandler(NameChangedEventKey,value);
}
remove{
listEventDelegates.RemoveHandler(NameChangedEventKey,value);
}
}


privatestringname;
publicstringName
{
get
{
returnname;
}
set
{
name=value;

if(listEventDelegates[NameChangedEventKey]!=null){
listEventDelegates[NameChangedEventKey].DynamicInvoke(newobject[]{this,null});
}

}
}
}
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

为什么使用EventHandlerList?这个问题之前就谈论过,默认情况下,客户端程序每为事件绑定一个处理程序,就需要在类型中产生一个delegate的引用,如此一来,如果事件很多的话,不利于较好地控制内存。但如果用EventHandlerList的话,则有利于统一管理所有的delegate
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: