C#事件與委托的區別


  1. 委托

事件是利用委托來定義的,因此先解釋委托。委托其實是一個類,它與其他類如string(引用類型)等沒有本質區別,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;

另外利用兩個函數來綁定與解除訂閱者的方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM