------事件与委托 (定义与用法) 事件与委托的区别 (委托是类型,事件是对象)

本文深入解析了委托与事件的概念及区别,通过实例演示了委托如何绑定和触发方法,以及事件如何提供更安全的触发机制。文章还展示了委托与事件在.NET编程中的应用。

1》

委托与事件的区别:

1.委托可以在声明它的类外部进行调用,而事件只能在类的内部进行调用。

2.委托是一个类型,事件修饰的是一个对象

总结:

总结: 参考资料:事件与委托的区别

1、委托可以把一个方法作为参数代入另一个方法。 委托可以理解为指向一个函数的指针。

2、委托和事件没有可比性,因为委托是类型,事件是对象

3、其实事件是委托的一个修饰符,加了event(事件)修饰之后,委托就被阉割了,假设这个加了修饰符的事件称为事件1,通过事件1我们可以更好地控制注册和注销,也就是对于一个外部类,那么他只能“注册自己+=、注销自己-=”,例如上面的ClassA,如果我们事件的注册是在ClassA内部进行的,那么它就只能注册自己内部的方法到事件上。另外,外界也不能主动地触发一个事件。事件只能add、remove自己,不能赋值。也就是说事件只能+=、-=,不能= 。当我们反编译以上例子的源程序的时候,我们可以发现事件内部就是一个private的委托和add,remove两个方法


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{

    //声明一个委托: 委托可以定义在类里面,但是一般我们不那样做,除非特殊情况。因为委托是和类平级的,所以委托一般定义在namespace下面
    //委托说白了就是一个数据类型,就像string 类型接收字符串数据 int类型接收整形数据, 而委托类型接收方法  
    public delegate void MyDelegate();

    public class Test
    {
        //创建一个委托的实例
        public MyDelegate mydel;

        //声明一个事件: 事件只能在类的内部声明
        public event MyDelegate EventMyDel;

        /// <summary>
        /// 事件触发机制(必须和事件在同一个类中)外界无法直接用EventMyDel()来触发事件
        /// </summary>
        public void DoEventMyDel()
        {
            //事件后面加一个括号,括号的意思就代表执行这个事件
            EventMyDel();
        }
    }


    public class Founc
    {
        public void Fun_A()
        {
            Console.WriteLine("A方法被触发");
        }

        public void Fun_B()
        {
            Console.WriteLine("B方法被触发");
        }

        public void Fun_C()
        {
            Console.WriteLine("C方法被触发");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Test test = new Test();
            Founc founc = new Founc();

            //注册委托(将委托绑定到方法)
            test.mydel = test.mydel + founc.Fun_A; //将委托实例挂载到了A方法 [注意,注册委托是可以用=号来进行注册的]
            test.mydel += founc.Fun_B; //将委托实例挂载到B方法

            //执行委托
            //test.mydel();  //输出结果是 [ A方法被触发 B方法被触发 ]

            //这时候我们来对委托进行干扰(其实这里的所谓的“干扰”,就是给以存在的委托链中附加了一个 null 的对象,然后在给委托附加C方法)
            test.mydel = null;
            test.mydel += founc.Fun_C;

            //再次执行委托(注意,先把上面那个执行委托注释掉,这样才能看到干扰后的结果嘛)
            test.mydel();  //输出结果  [ C方法被触发 ]




            /*大家想想,为什么会这样呢??为什么A,B方法不执行了呢??这是因为原来的委托链 是已经挂载了A,B两个方法了,但这时突然被干扰了下,又附加了一个null对象,破坏了原有的委托链了,但这又说明了什么呢?因为委托本质就是一个类, 它包含一对有用的字段,第一个字段是存放该对象的引用,第二个字段存放一个方法的指针,所以我们可以把委托理解成一个指向函数的指针,当一个方法作为参数 赋值给一个委托的时候,该委托就指向了该方法的首地址,即方法名,所以当我们给委托注册A,B两个方法,该委托就同时指向了A,B两个方法的首地址,但这 是又突然给委托赋值了,且赋值了一个null对象,注意这里用的是赋值符号[=],这就是说让该委托清除原有的指针指向,此时指向一个null,之后又给 委托注册了C方法,所以此时委托即指向null,又指向了C方法的首地址,这就是为什么运行时只会看到C方法被触发的原因了!

那就是说现在的委托变得不安全了,哪天一个项目中给委托注册了很多方法,但突然被干扰了下,前面的注册都失效了,那我们前面做的工作不是白做了,那有没有办法可以防止这种干扰呢??答案是当然有,相信聪明的你也应该猜到了,这时就是事件该上场的时候了。
*/

            /*==================================================*/



            //注册事件(将事件绑定到方法)。没法对事件用赋值[=]号来进行注册,需要用+=这种形式
            test.EventMyDel += founc.Fun_B;  //将事件绑定到B方法

            test.EventMyDel += null;  //即便这个时候对事件进行干扰 

            test.EventMyDel += founc.Fun_C; //将事件绑定到C方法

            //执行事件触发事件的方法 
            test.DoEventMyDel();  //输出结果是 [ B方法被触发 C方法被触发 ],即使你附加了一个null对象,2个方法照样依次执行了,,这就是事件的封装效果了

            Console.ReadKey();
        }
    }
}







<2>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 委托学习
{
    delegate int Mydelegate(int a, int b);//该委托的参数一定要与下面的M1方法参数一致,这样在把M1方法当做参数传给委托的时候就不会报错(错误1 :“M1”的重载均与委托“委托学习.Mydelegate”不匹配)

    public class A
    {
        public static int M1(int x, int y)
        {
            int z = x + y;
            return z;
        }

    }

    
    class Program
    {
        static void Main(string[] args)
        {
            //委托是对方法的封装
            Mydelegate d = new Mydelegate(A.M1); //实例化一个委托,注意M1方法后面是没有带小括号的,如果带小括号的话就等于执行该M1方法了,会报错的

           int sum=d(5, 6);
           Console.WriteLine(sum);
           Console.ReadKey();

        }
    }
}


<2>事件与委托的区别

通俗的讲,委托你可以在客户代码中直接调用委托来激发委托指向的函数,而事件不可以,事件的触发只能由服务代码自己触发

也就是说在你的代码里委托你不但可以安排谁是它的调用函数,还可以直接调用它,而事件不能直接调用,只能通过某些操作触发

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 委托学习2
{
    public delegate void Mydalegate(string message);

    //事件的本质就是一个委托。事件,就当给委托起了一个别名
    class EventClass
    {
        public event Mydalegate MyEvent;

        public void DoEvent(string mes) //注意这个方法参数要与委托的参数一致。
        {
            MyEvent(mes); 
        }
    }
    class Program
    {
        public void A(string mes)
        {
            Console.WriteLine(mes + "11111");
        }

        public void B(string mes)
        {
            Console.WriteLine(mes + "22222");
        }

        public void C(string mes)
        {
            Console.WriteLine(mes + "33333");
        }
        static void Main(string[] args)
        {

            //-----------------------------------------------------委托

            Program p=new Program ();

            //注册委托(将委托绑定到A方法)  ,非常重要的一点,委托是可以用=号来进行注册(挂载)的,而事件只能用+=来注册
            Mydalegate mydel = p.A;
            mydel("委托"); //执行委托,输出 委托11111

     

            //将委托再挂载到B方法,这时候委托就已经挂载到两个方法上了。形成了委托链
            mydel += p.B;
            mydel("委托"); //执行委托,输出 委托11111 委托22222



            //将委托链上的A方法删除掉
            mydel -= p.A;
            mydel("委托"); //执行委托,这里时候委托链上只有一个B方法了。所以这里输出 委托22222



            //那么现在对委托进行干扰。将委托重新指向了一个null,这时候他已经破坏了委托链了。之前注册的方法已经被清空。
            mydel = null;  
            //mydel("委托"); //报错:未将对象引用设置到对象的实例。

            //注册委托(将委托绑定到C方法)
            mydel += p.C;
            mydel("委托"); //执行委托,输出 委托33333
           
            //----------------------------------------------------事件


            EventClass e = new EventClass();

            //注册事件(将事件绑定到方法)。无法对事件用赋值[=]号来进行注册,需要用+=这种形式 ,这是一种规定 
            e.MyEvent += p.A;
            e.DoEvent("事件"); //执行DoEvent方法,方法内部是一个事件的执行。输出 事件11111

            e.MyEvent += p.B;

            e.DoEvent("事件"); //执行DoEvent方法,方法内部是一个事件的执行。输出事件11111 事件22222



            Console.ReadKey();
        }
    }
}


http://www.cnblogs.com/holyknight-zld/archive/2012/08/30/delegateEvent.html





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值