[原创]浅要分析委托和事件

学习了委托和事件,整理下我自己的脑袋,随便写写!

         什么是委托,从字面上理解就是“第三者”,就如c/c++里的(引用)指针,这里,委托引用的是方法,我们在讲到委托,一般和事件联系在一起。

在我的理解里,委托其实也没多大的重要作用,只是使你的程序设计更加灵活,更安全,就如索引器一样,换个方式,但是一个强大的程序语言都是灵活的!

实际上,windows编程是事件驱动编程,所以,有必要知道委托和事件,因为在c#里,委托和事件是联系在一起的,可以这么理解:事件是委托的对象!

下面,举个小例子,我们知道排序有升序和降序的,看程序清单:

using System;

namespace DelegateAndEvent

{

         public class ClassCun

         {

                   public static void ASC(int[]a)//升序

                   {

                            for(int i=0;i<a.Length;i++)

                            {

                                     for(int j=0;j<a.Length-1;j++)

                                     {

                                               if(a[j]>a[j+1])

                                               {

                                                        int temp=a[j];

                                                        a[j]=a[j+1];

                                                        a[j+1]=temp;

                                               }

                                     }

                                     Console.WriteLine(a[i]);

                            }      

                   }

                   public static void DEC(int[]a)//降序

                   {

                            for(int i=0;i<a.Length;i++)

                            {

                                     for(int j=0;j<a.Length-1;j++)

                                     {

                                               if(a[j]<a[j+1])

                                               {

                                                        int temp=a[j];

                                                        a[j]=a[j+1];

                                                        a[j+1]=temp;

                                               }

                                     }

                                     Console.WriteLine(a[i]);

                            }

                   }

         }

         public class main

         {

                   static void Main()

                   {

                            int[] a=new int[]{1,4,3,2};

                            //ClassCun.ASC(a);

                            ClassCun.DEC(a);

                   }

         }

}

这个用委托来实现的话,就要在这个类的外面定义个委托了,因为委托也是引用类型和类是同一级别的,好,我在类外面定义个委托:

public delegate void sort(int[]a);

 

ok,现在,主函数Main()里的代码就要变一下了,因为委托是类型,所以要创建个委托对象来调用的,好,我定义个委托对象:

sort ASCandDEC=new sort(ClassCun.ASC);//并引用升序的方法,参数那里是写方法名

如果是降序的话,就变成:

sort ASCandDEC=new sort(ClassCun.DEC);

―――――――――――――――――――

在这里,只是个简单的例子,所以有关的好处,优点没有表现出来,最直观的,程序多了种实现方式,更加灵活了!

―――――――――――――――――――――――――――――――――――――――――――――――――――――――

我们也可以看一下IL代码,利用ILDASM,我们定义的委托sort,如下图:


我们先来看一下这个委托的构造器.ctor


我分析一下:

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

可以看出,第一个参数是一个object类型的,如果实例化了,就是用new创建一个委托对象的时候,就是这个当前this(实例),但是,委托也可以是静态的,那么,这个object的值

也可以是null 第二个参数是这个实例的方法了。很简单的!

下面,我们看一下Main()里的代码:


其中,委托的代码:

IL_0012:  ldnull

IL_0013:  ldftn      void DelegateAndEvent.ClassCun::ASC(int32[ ])

 IL_0019:  newobj     instance void DelegateAndEvent.sort::.ctor(object, native int)

        

        

 IL_0021:  callvirt   instance void DelegateAndEvent.sort::Invoke(int32[])

分析下:

当我创建了一个委托的实例: sort ASCandDEC=new sort(ClassCun.ASC(a));

IL_0012:  ldnull  这个表示我们在静态的方法里(这里,我们是在Main(),Main()是静态的方法)对这个委托进行实例化。

如果,不是在静态的方法里给委托实例化的话,那么,这里的操作码就是ldarg.0,也就是this(当前对象的指针).

IL_0013:  ldftn      void DelegateAndEvent.ClassCun::ASC(int32[]) 是把一个指向需要委托的方法的指针装进堆栈中(内存)

IL_0019:  newobj     instance void DelegateAndEvent.sort::.ctor(object, native int)  这里就是我们new 的代码了

IL_0021:  callvirt   instance void DelegateAndEvent.sort::Invoke(int32[]) 最后调用这个委托

――――――――――――――――――

说了委托,那么,我们来说一下事件,windows应用程序实际上是事件驱动编程,点击一个按钮,关闭一个窗体,实际上都是一个事件

而,事件的定义,都是通过委托来的,我们在编写windows 程序的时候,没有看都到事件的委托定义,而直接在用事件了,其实,系统已经把

通用的事件封装好了,在windows.form这个类中已经定义好,下面,我们利用一个简单的例子来说明一下,事件是如何触发执行的:

using System;

namespace DelegateAndEvent

{

    public delegate void sort();//申明事件之前,必须先定义委托类型

    public class ClassCun

    {

        public event sort sortEvent;//定义个事件

        public int a;

        public int A

        {

            get{return a;}

            set{a=value;}

        }

        public void method(int b)

        {

            if(b!=0)

                a/=b;

            else

                sortEvent();

        }

    }

    public class main

    {

        static void Main()

        {

            ClassCun clsCun=new ClassCun();

            clsCun.a=5;

            clsCun.sortEvent+=new sort(clsCun_sortEvent);//订阅这个事件

            clsCun.method(Int32.Parse(Console.ReadLine()));//执行这个的时候,就会触发这个方法里的事件

        }

        private static void clsCun_sortEvent()//触发事件后,执行的代码

        {

            Console.WriteLine("a的值不能为0");

        }

    }

}

OK,我们可以调试看一下,是不是像我说的那样,执行这个方法后,触发事件,跳转到事件执行代码那里,设个断点,输入一个0


F11


再按F11,运行到这里:


看到没,跳转到了这里了!

当然,如果利用ILDASM的话,我们可以在Main里看到这样的一段代码:

<!--[if !vml]--><!--[endif]-->

 

大家有没有看出,这段代码和文章开头的排序例子,在Main()函数里,实例化一个委托类型的代码很相似啊:

IL_0012:  ldnull

IL_0013:  ldftn      void DelegateAndEvent.ClassCun::ASC(int32[ ] )

 

这样,我们也可以总结出:事件的触发执行,和委托的实例化,调用一样!

――――――――――――――――――――――――――――――――――――――

写这篇文章,主要是为了理清下自己的思路,多少难免有些地方一笔带过的,有什么问题,欢迎大家一起讨论! 

posted on 2007-08-10 06:09  寸芒  阅读(283)  评论(1编辑  收藏  举报

导航