事件模式与观察者模式

来源:互联网 发布:java catch return 编辑:程序博客网 时间:2024/05/22 08:22



学习C#的事件模式Delegateevent这二个概念比较难理解,因为这二个都被设计成关键字,想进一步查看其定义和实现就没有下文了,不过再难也得硬着头皮弄明白,我以前好长时间都是似懂非懂的状态,后来在学习了观察者设计模式和IL后利用这二者的知识来理解就比较容易。下面我就用观察者设计模式和IL来分析一下事件模式中Delegateevent这二个关键字。

        首先,我们来了解一下delegate究竟是什么东西,先来看一下下面的程序(为了演示,代码尽量简略)。

       Using System;

public class Test

{

           public delegatevoid aaa();

            public static void Main(String[]args) {      

                     aaaa=new aaa(show);

                     a();

          }

        

           public static voidshow()

           {

                     Console.WriteLine("hi");

           }

}

        以上代码用csc.exe编译后再用ILDASM反编译成文本文件:

.class public auto ansibeforefieldinit Test  extends [mscorlib]System.Object

{

 .class auto ansisealed nestedpublicaaa  extends[mscorlib]System.MulticastDelegate

 {

   .method public hidebysig specialnamertspecialname  instance void .ctor(object 'object', native int'method') runtime managed

   {

   } // end of method aaa::.ctor

   .method public hidebysig newslotvirtual instance void Invoke() runtime managed

   {

   } //end of method aaa::Invoke

 

   .method public hidebysig newslotvirtual instance class[mscorlib]System.IAsyncResult  BeginInvoke(class [mscorlib]System.AsyncCallback callback,

                       object 'object')runtime managed

   {

   } // end of method aaa::BeginInvoke

 

   .method public hidebysig newslotvirtual instance void EndInvoke(class [mscorlib]System.IAsyncResultresult) runtime managed

   {

   } // end of method aaa::EndInvoke

 

 } // end of class aaa

 

 .method public hidebysig static void Main(string[] args) cil managed

 {

   .entrypoint

   //

   .maxstack 2

   .locals init (class Test/aaa V_0)

   IL_0000: nop

IL_0001: ldnull

//show方法的指针推送到计算堆栈上

   IL_0002: ldftn     void Test::show()

   IL_0008: newobj    instance voidTest/aaa::.ctor(object,

                                                      native int)

   IL_000d: stloc.0

   IL_000e: ldloc.0

   IL_000f: callvirt  instance voidTest/aaa::Invoke()

   IL_0014: nop

   IL_0015: ret

 } // end of method Test::Main

 

 .method public hidebysig static void show() cil managed

 {

   //

   .maxstack 8

   IL_0000: nop

   IL_0001: ldstr     "hi"

   IL_0006: call      void[mscorlib]System.Console::WriteLine(string)

   IL_000b: nop

   IL_000c: ret

 } // end of method Test::show

 

 .method public hidebysig specialnamertspecialname

         instance void .ctor() cil managed

 {

   //

   .maxstack 8

   IL_0000: ldarg.0

   IL_0001: call      instance void[mscorlib]System.Object::.ctor()

   IL_0006: ret

 } // end of method Test::.ctor

 

} // end of class Test

 

        从反编译出来IL指令中可以看到delegate关键字修饰的aaa由编译器转换为一个继承自System.MulticastDelegate的类然后在main方法中以方法show的指针作参数构造一个aaa的实例,后面再通过该实例调用Invoke方法,相信至此对delegate关键字应该明白其作用了。

要了解事件模式的话,光是了解delegate还不够,我们还得看看event是什么玩艺:

using System;

 

public class Test {

    public static voidMain(String[] args) {      

                  EventTest et = newEventTest();

           et.OnPropertyChanged+=show;

                   et.Age=2;

    }

         public static void show()

         {

                 Console.WriteLine("event trigged");

         }       

}

 

  public class EventTest

  {     

         public delegate voidPropertyChangedHandler();

         public eventPropertyChangedHandler OnPropertyChanged;

          

         private int age;

        public int Age

        {

             get { return age; }

             set

                           {

                            age = value;

                                     if(OnPropertyChanged!=null)

                                     {

                                              OnPropertyChanged();

                                     }

                            }

       }

  }

 

学过MVVM模式的朋友对以上代码是否有似曾相识的感觉,用csc.exe编译后再用ILDASM反编译成文本文件:

.class public auto ansi beforefieldinit Test extends[mscorlib]System.Object

{

 .method public hidebysig staticvoid Main(string[] args) cil managed

 {

   .entrypoint

   //

   .maxstack 3

   .locals init (class EventTestV_0)

   IL_0000: nop

   IL_0001: newobj    instance voidEventTest::.ctor()

   IL_0006: stloc.0

   IL_0007: ldloc.0

   IL_0008: ldnull

   IL_0009: ldftn     void Test::show()

   IL_000f: newobj    instance void EventTest/PropertyChangedHandler::.ctor(object,native int)

   IL_0014: callvirt  instance void EventTest::add_OnPropertyChanged(classEventTest/PropertyChangedHandler)

   IL_0019: nop

   IL_001a: ldloc.0

   IL_001b: ldc.i4.2

   IL_001c: callvirt  instance void EventTest::set_Age(int32)

   IL_0021: nop

   IL_0022: ret

 } // end of method Test::Main

 

 .method public hidebysig staticvoid show() cil managed

 {

   //

   .maxstack 8

   IL_0000: nop

   IL_0001: ldstr     "event trigged"

   IL_0006: call      void [mscorlib]System.Console::WriteLine(string)

   IL_000b: nop

   IL_000c: ret

 } // end of method Test::show

 

 .method public hidebysigspecialname rtspecialname instancevoid .ctor() cil managed

 {

   //

   .maxstack 8

   IL_0000: ldarg.0

   IL_0001: call      instance void [mscorlib]System.Object::.ctor()

   IL_0006: ret

 } // end of method Test::.ctor

 

} // end of class Test

 

.class public auto ansi beforefieldinitEventTest extends [mscorlib]System.Object

{

 .class auto ansi sealed nestedpublic PropertyChangedHandler extends[mscorlib]System.MulticastDelegate

 {

   .method public hidebysigspecialname rtspecialname instancevoid .ctor(object 'object',  native int 'method') runtime managed

   {

   } // end of methodPropertyChangedHandler::.ctor

 

   .method public hidebysig newslotvirtual  instance void Invoke() runtime managed

   {

   } // end of methodPropertyChangedHandler::Invoke

 

   .method public hidebysig newslotvirtual instance class[mscorlib]System.IAsyncResult

           BeginInvoke(class[mscorlib]System.AsyncCallback callback, object 'object') runtime managed

   {

   } // end of methodPropertyChangedHandler::BeginInvoke

 

   .method public hidebysig newslotvirtual instance void EndInvoke(class [mscorlib]System.IAsyncResultresult) runtime managed

   {

   } // end of methodPropertyChangedHandler::EndInvoke

 

 } // end of classPropertyChangedHandler

 

 .field private classEventTest/PropertyChangedHandlerOnPropertyChanged

 .field private int32 age

 .method public hidebysigspecialname instance void add_OnPropertyChanged(classEventTest/PropertyChangedHandler 'value') cil managed

 {

   //

   .maxstack 3

   .locals init (classEventTest/PropertyChangedHandler V_0,

            classEventTest/PropertyChangedHandler V_1,

            classEventTest/PropertyChangedHandler V_2,

            bool V_3)

   IL_0000: ldarg.0

   IL_0001: ldfld     class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged

   IL_0006: stloc.0

   IL_0007: ldloc.0

   IL_0008: stloc.1

   IL_0009: ldloc.1

   IL_000a: ldarg.1

   IL_000b: call      class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class[mscorlib]System.Delegate,

                                                                                           class [mscorlib]System.Delegate)

   IL_0010: castclass EventTest/PropertyChangedHandler

   IL_0015: stloc.2

   IL_0016: ldarg.0

   IL_0017: ldflda    class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged

   IL_001c: ldloc.2

   IL_001d: ldloc.1

   IL_001e: call      !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<classEventTest/PropertyChangedHandler>(!!0&, !!0,  !!0)

   IL_0023: stloc.0

   IL_0024: ldloc.0

   IL_0025: ldloc.1

   IL_0026: ceq

   IL_0028: ldc.i4.0

   IL_0029: ceq

   IL_002b: stloc.3

   IL_002c: ldloc.3

   IL_002d: brtrue.s  IL_0007

 

   IL_002f: ret

 } // end of methodEventTest::add_OnPropertyChanged

 

 .method public hidebysigspecialname instance void

         remove_OnPropertyChanged(classEventTest/PropertyChangedHandler 'value') cil managed

 {

   //

   .maxstack 3

   .locals init (classEventTest/PropertyChangedHandler V_0,

            classEventTest/PropertyChangedHandler V_1,

            classEventTest/PropertyChangedHandler V_2,

            bool V_3)

   IL_0000: ldarg.0

   IL_0001: ldfld     class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged

   IL_0006: stloc.0

   IL_0007: ldloc.0

   IL_0008: stloc.1

   IL_0009: ldloc.1

   IL_000a: ldarg.1

   IL_000b: call      class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,

                                                                                          class [mscorlib]System.Delegate)

   IL_0010: castclass EventTest/PropertyChangedHandler

   IL_0015: stloc.2

   IL_0016: ldarg.0

   IL_0017: ldflda    class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged

   IL_001c: ldloc.2

   IL_001d: ldloc.1

   IL_001e: call      !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<classEventTest/PropertyChangedHandler>(!!0, !!0, !!0)

   IL_0023: stloc.0

   IL_0024: ldloc.0

   IL_0025: ldloc.1

   IL_0026: ceq

   IL_0028: ldc.i4.0

   IL_0029: ceq

   IL_002b: stloc.3

   IL_002c: ldloc.3

   IL_002d: brtrue.s  IL_0007

 

   IL_002f: ret

 } // end of methodEventTest::remove_OnPropertyChanged

 

 .method public hidebysigspecialname instance int32  get_Age() cil managed

 {

   //

   .maxstack 1

   .locals init (int32 V_0)

   IL_0000: nop

   IL_0001: ldarg.0

   IL_0002: ldfld     int32 EventTest::age

   IL_0007: stloc.0

   IL_0008: br.s      IL_000a

 

   IL_000a: ldloc.0

   IL_000b: ret

 } // end of methodEventTest::get_Age

 

 .method public hidebysigspecialname instance void set_Age(int32'value') cil managed

 {

   //

   .maxstack 2

   .locals init (bool V_0)

   IL_0000: nop

   IL_0001: ldarg.0

   IL_0002: ldarg.1

   IL_0003: stfld     int32 EventTest::age

   IL_0008: ldarg.0

   IL_0009: ldfld     class EventTest/PropertyChangedHandlerEventTest::OnPropertyChanged

   IL_000e: ldnull

   IL_000f: ceq

   IL_0011: stloc.0

   IL_0012: ldloc.0

   IL_0013: brtrue.s  IL_0023

 

   IL_0015: nop

   IL_0016: ldarg.0

   IL_0017: ldfld     class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged

   IL_001c: callvirt  instance void EventTest/PropertyChangedHandler::Invoke()

   IL_0021: nop

   IL_0022: nop

   IL_0023: ret

 } // end of methodEventTest::set_Age

 

 .method public hidebysigspecialname rtspecialname instance void .ctor() cil managed

 {

   //

   .maxstack 8

   IL_0000: ldarg.0

   IL_0001: call      instance void [mscorlib]System.Object::.ctor()

   IL_0006: ret

 } // end of methodEventTest::.ctor

 

 .eventEventTest/PropertyChangedHandler OnPropertyChanged

 {

   .addon instancevoid EventTest::add_OnPropertyChanged(class EventTest/PropertyChangedHandler)

   .removeoninstance void EventTest::remove_OnPropertyChanged(classEventTest/PropertyChangedHandler)

 } // end of eventEventTest::OnPropertyChanged

 .property instance int32 Age()

 {

   .get instance int32EventTest::get_Age()

   .set instance voidEventTest::set_Age(int32)

 } // end of propertyEventTest::Age

} // end of class EventTest

 

event声明事件后编译器在编译时给类中加了二个方法:

add_OnPropertyChanged(class EventTest/PropertyChangedHandler 'value')

remove _OnPropertyChanged(class EventTest/PropertyChangedHandler 'value')

在这二个方法中有二个调用:

System.Delegate::Combine(class [mscorlib]System.Delegate, class[mscorlib]System.Delegate)

System.Delegate::Remove(class[mscorlib]System.Delegate, class[mscorlib]System.Delegate)

查一下MSDN这二个调用是干什么的

Combine方法将两个委托的调用列表连接在一起Remove方法从一个委托的调用列表中移除另一个委托的最后一个调用列表

委托里有个调用列表!

挖到这里,学过观察者模式的朋友是否有似曾相识的感觉:观察者模式中被观察者也有一个订阅者列表,有AddRemove方法。事件模式不就是观察者模式吗?,不过在C#中用delegate来实现观察者模式中的更新状态的接口和订阅者列表,event关键字实现的订阅者的添加和删除。

   理解了事件模式和观察者模式的关系,对MVVM模式中的Notification类也就不难理解了。

 




0 0
原创粉丝点击