zoukankan      html  css  js  c++  java
  • C#事件与委托的区别

    C#事件与委托的区别

    1. 委托

    事件是利用委托来定义的,因此先解释委托。委托是一个类,它与其他类如int,string等没有本质区别,int代表的是所有的整形,而string代表的是字符串,委托则代表的是一类方法,这类方法具有相同返回类型和相同参数。委托的定义:

      public delegate void CalculatorHandler(int x,int y);

    从CalculatorHandler这个委托的定义可以看出,它反应的是一类方法,这类方法的返回类型是void,两个参数是(int x,int y),因此以后所有具有这样特征的方法都可以用这个委托来代替,现有以下这个方法:

         static void Add(int x, int y)
            {
               Console.WriteLine("x+y={0}",x+y);
            }

    首先要将这个方法赋值给这个委托才可以使用,就如普通的类赋值一样,

    CalculatorHandler calhandler = new CalculatorHandler(Add)

    当然你也可以像给一个整形赋值一样,这样赋值:

    CalculatorHandler calhander = Add;

    当要调用这个方法的时候,你可以就像使用方法一样使用委托,

    calhander(3,4);

    委托也可以绑定多个方法,当调用这个委托时,会调用所有已经绑定了的方法,如现在还有这样的方法:

            static void Multiply(int x, int y)
            {
                Console.WriteLine("x*y={0}",x*y);
            }

    只需在calhandler基础上多绑定个方法,具体语法:

    calhander += Multiply;

    这样当调用

    calhander(3,4);

    会同时调用Add和Multiply这两个方法,你也可以利用“-=”解绑方法:

    calhander -= Multiply;

    这样再次调用这个委托,则只会调用Add这个方法。

    2. 事件

    一说到事件总会有发布者(publisher)和订阅者(subscriber),发布者定义了一个事件,订阅者订阅了该事件(指的是当该事件触发时,订阅者做出什么样的反应,即利用相应的函数去处理)。该函数的定义与定义该事件的委托配套。代码如下:

    复制代码
    public delegate void MessageEventHandler();
        class Publisher
        {
            public event MessageEventHandler MessageEvent;
            public void DoSomething()
            {
                Console.WriteLine("等待消息");
                Console.WriteLine("首长来啦!!!");
                OnMessageEvent();
            }
            public void OnMessageEvent()
            {
                if (MessageEvent != null)
                {
                    MessageEvent();
                }
            }
        }
        class Subscriber
        {
            public Subscriber(Publisher p)
            {
                p.MessageEvent += Response;
            }
    
            public void Response()
            {
                Console.WriteLine("首场,辛苦了");
            }
    }
    
        class Program
        {
            static void Main(string[] args)
            {
                Publisher p = new Publisher();
                Subscriber s = new Subscriber(p);
                p.DoSomething();
                Console.ReadKey();
            }
        }
    }
    复制代码

    这就是事件的基本用法,但是事件与委托到底有什么区别呢,从上面的代码可以看出,事件是根据委托来定义的,

    public event MessageEventHandler MessageEvent

    其实它是利用委托来规定订阅者处理函数的类型(相同的返回类型和参数即为一类),然后可以方便在发布者自身的类中来触发订阅者的一些方法。

    但是为什么要事件呢,要实现这些,我仅用委托也可以实现呀,如下代码:

    复制代码
     public delegate void MessageEventHandler();
        class Publisher
        {
            public MessageEventHandler MessageEvent;//为了方便,委托名与原来的事件名相同。
           // public event MessageEventHandler MessageEvent;
            public void DoSomething()
            {
                Console.WriteLine("等待消息");
                Console.WriteLine("首长来啦!!!");
                OnMessageEvent();
            }
            public void OnMessageEvent()
            {
                if (MessageEvent != null)
                {
                    MessageEvent();
                }
            }
        }
        class Subscriber
        {
            public Subscriber(Publisher p)
            {
                p.MessageEvent += Response;
            }
    
            public void Response()
            {
                Console.WriteLine("首场,辛苦了");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                Publisher p = new Publisher();
                Subscriber s = new Subscriber(p);
                p.DoSomething();
                Console.ReadKey();
            }
    }
    复制代码

    这样子也同样可以产生相同的结果。

    但是当客户端如下调用呢?

     Publisher p = new Publisher();
     Subscriber s = new Subscriber(p);
     p.DoSomething();
     p.MessageEvent();
     Console.ReadKey();

    客户端是不是能随意让发布者产生事件,因此我们可否将发布者的委托定义为private,因为只有发布者的内部才能触发事件嘛,其他人怎么可以?但是这样订阅者就无法订阅了,那我们是否可以增加绑定可解除的函数来订阅此委托呢?

    复制代码
    public delegate void MessageEventHandler();
        class Publisher
        {
            private MessageEventHandler MessageEvent;
           // public event MessageEventHandler MessageEvent;
            public void DoSomething()
            {
                Console.WriteLine("等待消息");
                Console.WriteLine("首长来啦!!!");
                OnMessageEvent();
            }
            public void OnMessageEvent()
            {
                if (MessageEvent != null)
                {
                    MessageEvent();
                }
            }
            public void Add_MessageEvent(MessageEventHandler m)
            {
                MessageEvent += m;               
            }
            public void Reomove_MessageEvent(MessageEventHandler m)
            {
                MessageEvent -= m;
            }
        }
        class Subscriber
        {
            public Subscriber(Publisher p)
            {
                //p.MessageEvent += Response;
                p.Add_MessageEvent(Response);
            }
    
            public void Response()
            {
                Console.WriteLine("首场,辛苦了");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                Publisher p = new Publisher();
                Subscriber s = new Subscriber(p);
                p.DoSomething();           
                Console.ReadKey();
            }
        }
    }
    复制代码

    这样就可以实现与事件一样的功能,因此为了方便微软为我们提供了事件访问器,何为事件访问器?

    复制代码
    public delegate void MessageEventHandler();
        class Publisher
        {
            private MessageEventHandler MessageEvent;
           // public event MessageEventHandler MessageEvent;
    
            public event MessageEventHandler TestEvent
            {
                add
                {
                    lock (MessageEvent)
                    {
                        MessageEvent += value;
                    }
                }
                remove
                {
                    lock (MessageEvent)
                    {
                        MessageEvent -= value;
                    }
    
                }
            }
            public void DoSomething()
            {
                Console.WriteLine("等待消息");
                Console.WriteLine("首长来啦!!!");
                OnMessageEvent();
            }
            public void OnMessageEvent()
            {
                if (MessageEvent != null)
                {
                    MessageEvent();
                }
            }
    
        }
        class Subscriber
        {
            public Subscriber(Publisher p)
            {
                p.TestEvent += Response;
                
            }
    
            public void Response()
            {
                Console.WriteLine("首场,辛苦了");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                Publisher p = new Publisher();
                Subscriber s = new Subscriber(p);
                p.DoSomething();           
                Console.ReadKey();
            }
    }
    复制代码

    以上的代码就是利用事件访问器来让委托绑定订阅者的方法,事件访问器中的add和remove能自动编译为+=和-=。

    通过reflector,我们可以看到一个事件是如何定义的:

    它是申明一个私有的委托:

    private MessageEventHandler MessageEvent;

    另外利用两个函数来绑定与解除订阅者的方法。

     
     
    分类: C#
  • 相关阅读:
    2015年北京大学软件project学科优秀大学生夏令营上机考试---C:单词翻转面试题
    跟我学Java多线程——线程池与堵塞队列
    Swift学习——类的定义,使用,继承,构造等(五)
    LNMP编译安装(centos7+nginx1.9+mysql5.6+php5.5)
    【iOS开发系列】九宫格布局
    出现异常时直接把e输出比输出e.getMessage()好得多
    往服务器上传个文件只要不到10毫秒,往数据库写条记录却要10秒
    使用struts的logic:iterate标签遍历列表时得到显示序号
    一次性上传多个文件到服务器端(一)
    Another MySQL daemon already running with the same unix socket的解决
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3562557.html
Copyright © 2011-2022 走看看