[原创]浅要分析委托和事件
学习了委托和事件,整理下我自己的脑袋,随便写写!
什么是委托,从字面上理解就是“第三者”,就如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
{
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
{
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里看到这样的一段代码:
大家有没有看出,这段代码和文章开头的排序例子,在Main()函数里,实例化一个委托类型的代码很相似啊:
IL_0012: ldnull
IL_0013: ldftn void DelegateAndEvent.ClassCun::ASC(int32[ ] )
这样,我们也可以总结出:事件的触发执行,和委托的实例化,调用一样!
――――――――――――――――――――――――――――――――――――――