C#委託、事件剖析(下)

本節對事件進行總結。

2、事件:

一、概念:Event:A member that enables an object or class to provide notifications;官方的解釋是這樣,就是說在C#中,事件是使

對象或者類具有通知能力的成員。好比說手機收到短信提醒我去開會,那麼手機就充當了一個具有通知能力的成員。說白了,事件

的做用就是對象和類之間的信息傳遞的橋樑。

二、原理:源於發生-響應模型:

事件源(event source) + 事件自己(event) => 事件的訂閱者(event subscriber) + 事件處理器(event handler)           

(另外還有事件的訂閱者和事件源之間的訂閱關係subscribe relationship)

仍是以手機收到短信提醒我去開會爲例,事件源:手機嗎,事件:收到短信,事件的訂閱者:我,事件處理器:去開會,訂閱關係:我訂閱手機

三、事件的聲明:分爲詳細聲明和簡略聲明:

(1)詳細聲明:

public delegate void MyDelegateEventHandler();
    public class Event
    {
        private MyDelegateEventHandler myDelegateEventHandler;
        public event MyDelegateEventHandler MyDelegate
        {
            add
            {
                this.myDelegateEventHandler += value;
            }
            remove
            {
                this.myDelegateEventHandler -= value;
            }
        }
    }

(2)簡略說明:

public delegate void MyDelegateEventHandler();
    public class Event
    {
         public event MyDelegateEventHandler myDelegate;
    }

能夠看到,在完整聲明中首先添加了一個委託類型的字段,而後暴漏了添加和移除事件處理器的功能,可是咱們常常用的是簡略聲明,由於代碼更加簡潔,

能夠看出事件對外界隱藏了大部分功能,它的本質就是對其中委託字段的一個封裝(encapsulation),防止外界偷用濫用委託字段。

那麼問題來了:第一個問題:有了委託爲何還會有事件呢,事件內部不就是委託嗎,緣由是爲了防止public型的委託字段在外面被濫用,好比委託能夠用invoke調用,

可是事件只能在+=或-=的左側,這樣就增長了整個程序的安全性。

第二個問題:那委託和事件的關係什麼樣的呢?咱們說事件是基於委託的。一方面,事件須要委託來作一個約束,這個約束規定了事件源發送什麼要求給事件的訂閱者,

事件訂閱者的事件處理器必須和這個約束相對應才能夠訂閱這個事件,另外一方面,事件訂閱者收到事件之後作出事件處理器,而這個事件處理器必須經過委託才能夠作到。

四、簡單實例:

Example:作一個窗口,有文本框和按鈕,點擊按鈕文本框顯示時間,不用WindowsForms

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ConsoleApp14
{
    class Program
    {
        public static TextBox textBox;
        public static Button button;
        static void Main(string[] args)
        {
            Form form = new Form();
            TextBox textBox = new TextBox();
            Button button = new Button();
            form.Controls.Add(textBox);
            form.Controls.Add(button);
            textBox.Width = 400;
            button.Top = 100;
            button.Click += Button_Click;
            form.ShowDialog();
        }

        private static void Button_Click(object sender, EventArgs e)
        {
            textBox.Text = DateTime.Now.ToString();
        }
    }
}

 

這裏舉的事例就是windowsforms內部的代碼,咱們說事件自己是不會發生的是由事件源內部的邏輯所觸發,在本例中,並非人按了按鈕而後按鈕觸發了事件,

這其中還有一個小過程,就是當按鈕被key down再key up時,向程序內部發送了一系列電訊號,通知電腦,而後再發生事件,

五、聲明事件的相關約定:

用於聲明事件的委託通常用:事件+EvnetHandler,參數通常有2個,第一個事件源,第二個EventArgs的派生類,用於觸發事件的方法名通常爲On+方法名,

訪問級別Protected。可能有點蒙,舉個實例就懂了。

Example:舉一個顧客在KFC點餐的例子

namespace ConsoleApp15
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();
            Waitor waitor = new Waitor();
            customer.Order += waitor.Serve;
            customer.Eat();
            customer.Pay();
        }
    }
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
    public class Customer
    {
        public int Money { get; set; }
        public event OrderEventHandler Order;
        public void Pay()
        {
            Console.WriteLine($"OK,{Money} dollars");
        }
        public void Eat()
        {
            Console.WriteLine("Let's go to the KFC...");
            Console.WriteLine("Stand in front of the waitor...");
            Console.WriteLine("A hamburger,Please...");
            OnOrder();
        }
        protected void OnOrder()
        {
            OrderEventArgs orderEventArgs = new OrderEventArgs();
            orderEventArgs.Snack = "Hamburger";
            orderEventArgs.Size = "large";
            this.Order.Invoke(this, orderEventArgs);

        }
    }
    public class OrderEventArgs : EventArgs
    {
        public string Snack { get; set; }
        public string Size { get; set; }
    }
    class Waitor
    {
        public void Serve(Customer customer, OrderEventArgs e)
        {
            Console.WriteLine($"Here is your snack {e.Snack}");
            int price = 20;
            switch (e.Size)
            {
                case "large":
                    price *= 2;
                    break;
                case "small":
                    price *= 1;
                    break;
                default:
                    break;
            }
            customer.Money += price;
        }
    }
}

 

按照事件的五個要素,首先須要事件源,作一個Customer類,還須要一個事件訂閱者,作一個Waitor類,而後根據訂閱關係去寫具體的方法,訂閱關係customer.Order += waitor.Serve; Customer點餐Waitor服務,waitor類中上餐並算好價格,這個時候須要一個事件處理器OrderEventHandler,這個委託的參數須要一個OrderEventArgs,建立這個類寫好屬性,在寫好委託和事件,而後在Customer類中寫點餐事件,點餐事件爲Protected的,和public型的委託字段同樣防止被外界濫用,提升安全性。

想融會貫通其實也不難,只須要將事件的5個要素每個列舉出來,那麼最後事件也就出來了。

 

至此事件總結完畢,有不明之處還請指教。                2018-08-17   16:43:19

相關文章
相關標籤/搜索