c#之事件詳解


1.初步了解:

(1)事件:指的是能夠發生的什么事情。比如公司上市,這里的上市就是事件(比事情更正式。)。

(2)在c#中的定義:是類型的成員。是一種使對象或類具備了通知能力的成員。

(3)事件參數:經由事件發送過來的,與事件本身相關的消息,稱為事件參數。

         作用:比如,當手機的關注者收到通知之后,就會檢查事件參數(這里的包含這個通知中具體是開會還是別的信息),根據事件參數中的內容采取相應的行動。

(4)微事件處理器:軟對這種對響應做出的相應處理稱為響應事件或者處理事件,處理事件中具體所做的事情就叫做事件處理器。

(5)事件=使對象或類具備通知的能力+可選的事件參數(就是指的傳來的詳細信息)

(6)使用環境:用於對象或類之間的動作協調與信息傳遞(消息推送)。

某某對象有什么事件,是指這個對象可以通過這個事件來通知別的對象,事件一發生,關心這個事件的對象就會做出響應進行相應的處理。

(7)事件模型(它是從現實生活中抽象出來的一個客觀存在)

發生->響應中的5個部分:鬧鍾響了你起床,孩子餓了你做飯。這2個例子都只有4部分,鬧鍾,響了,你,起床;孩子,餓了,你,做飯。還缺最后一部分,就是訂閱關系。就是說你關注着某個事件。比如說為什么別人的鬧鍾響你不起床呢,因為你指訂閱了自己的鬧鍾的事件,並且對事件做出了響應。

發生->響應中的5個動作(步驟):(1)我有一個事件。(2)一個人或一群人關心這個事件(3)我的事件發生了(4)關心這個事件的人依次接到通知(5)被通知到的人根據拿到的事件信息(又稱事件數據,事件參數,通知)對事件進行響應(又稱事件處理器)

(8)事件多用於桌面手機等的客戶端編程。

2.事件的應用

事件不會主動發生,一定是事件的擁有者的內部邏輯觸發的。

(1)事件模型的5個組成部分

  ·事件的擁有者(event source,對象)

 ·事件成員(event,成員)

 ·事件的響應者(event subscriber,對象)

 ·事件處理器(event handler,成員)--本質是一個回調方法

 ·事件訂閱     把事件處理器和事件關聯起來,本質上是一種以委托類型為基礎的約定。用於訂閱事件的事件處理器必須和事件遵守同一個約定。這個約定既約定了事件能夠把什么樣的消息發送給事件處理器,也約束了事件處理器能夠處理什么樣的消息。如果想訂閱的事件和事件處理器遵守的約定是一樣的,那就能夠匹配。這個約定就是委托。所以常常說事件是基於委托的。之所以必須基於委托是因為這個事件處理器只能干這個事件所能允許干的事情,如果沒有這個委托約束的話,比如說孩子餓了,事件處理器去打游戲,再比如說孩子困了,事件處理器去唱歌,這完全不符合常理,所以必須要有委托約束限制誰能來訂閱我這個事件,事件處理器能夠干什么。

 

  class Program
    {
        static void Main(string[] args)
        {
            //timer事件擁有者
            Timer timer = new Timer();
            //boy是事件響應者
            Boy boy = new Boy();
            timer.Interval = 1000;
            //+=表示事件訂閱,其中Elapsed是事件 ,其實我們可以先寫Action方法名,這時候編譯器會報錯,
//然后根據報錯提示自動在Boy類中生成Action這個事件的處理器方法就可以,因為一般初學者不知道Elaped等其它事件的約定是什么。可以通過編譯器來實現
timer.Elapsed += boy.Action; timer.Start(); Console.ReadKey(); } } public class Boy { /// <summary> /// 事件處理器 /// </summary> /// <param name="sender">這是事件的擁有者,事件的source,或者事件的發送者(這三個說法都一樣)</param> /// <param name="e">事件參數</param> internal void Action(object sender, ElapsedEventArgs e) { Console.WriteLine("elapsedEventArgs"); } }

事件的擁有者是timer,事件的響應者是類Boy,事件處理器Action是自己定義的一個方法,定時執行的方法。響應者訂閱了之后就會定時執行這個事件處理器方法

(2)下面是事件的擁有者和響應者是不同的對象。

下面的代碼是上圖中的格式,事件的響應者和擁有者是不同的對象。

    class Program
    {
        static void Main(string[] args)
        {
            //form是事件擁有者
            Form form = new Form();
            //controller是事件響應者
            Controller controller = new Controller(form);
            Console.ReadKey(); 
        } 
    }
    public class Controller
    {

        private Form form;
        public   Controller(Form form)
        {
            if(form!=null)
            {
                this.form = form;
                //事件是Click。
                //事件處理器訂閱事件FormClicked。
                this.form.Click += this.FormClicked;
            } 
        } 
        /// <summary>
        /// 事件處理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormClicked(object sender, EventArgs e)
        {
            this.form.Text = "test";
        }
    }
     

 

 

(3)事件的擁有者和響應者是同一對象。

代碼如下:

   class Program
    {
        static void Main(string[] args)
        {
            //form是事件擁有者
            MyForm form = new MyForm();
            form.Click += form.FormClicked;
            Console.ReadKey(); 
        } 
    }
    public class MyForm:Form
    { 
        /// <summary>
        /// 事件處理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void FormClicked(object sender, EventArgs e)
        {
            this.Text = "test";
        }
    }

(4)事件的擁有者是事件的相應者的一個字段成員,事件的響應者用方法訂閱者自己的成員的某個事件。

實現點擊按鈕,在文本框中顯示文本信息

 class Program
    {
        static void Main(string[] args)
        {
            //form是事件擁有者,也是事件的響應者
            MyForm form = new MyForm();
            form.ShowDialog();
            Console.ReadKey(); 
        } 
    }
    public class MyForm:Form
    {
        private TextBox textBox;
        private Button button;
        public MyForm()
        {
            this.textBox = new TextBox();
            this.button = new Button();
            this.Controls.Add(textBox);
            this.Controls.Add(button);
            //Click是事件,ButtonCliked訂閱了事件Click  注意,如果已經自己拖拽了控件,那就寫自己定義非控件名稱,比如:this.button1.Click   
            this.button.Click += this.ButtonCliked; 
        }
        /// <summary>
        /// 事件處理器
        /// </summary>
        /// <param name="sender">這是事件的擁有者,事件的source,或者事件的發送者</param>
        /// <param name="e">事件參數</param>
        private void ButtonCliked(object sender, EventArgs e)
        {
            if(sender==this.button)
            {
                this.textBox.Text = "test";
            }
           
        }
    }

結果:

 

 

示例2(引用於:https://www.cnblogs.com/wayfarer/archive/2004/04/20/6712.html): 

創建一個簡單的類,名為FileWatch,包含事件OnfileChange。該類將檢查在執行應用程序的目錄(當前

目錄,通常是項目名/bin/debug)下,是否存在文件test.txt。如果文件被刪除或創建,都將觸發事件。

同時提供一個方法MonitorFile以不斷地查詢該文件。

建立事件的要點:

(1)首先要創建一個委托FileWatchEventHandler,因為事件是基於委托的,是通過委托來進行約束事件響應器和事件的。

(2)然后創建一個事件字段FileWatchEvent,返回類型是委托類型。

(3)然后定義一個方法OnFileChangeEvent處理事件。

(4)總體來說就是Monitor()方法引起事件的產生,通過委托的約束,訂閱了這個事件的響應者進行事件的處理,也就是執行OnFileChange()方法。

namespace MyEvent
{
    /** 
     * 首先線程啟動(thd.Start()),然后調用MonitorFile()方法。引起事件產生,FileWatchEvent產生后,
由於我們將事件FileWatchEvent綁定到了OnFileChange()方法上。因而調用本地即窗口類的OnFileChange()方法,從而實現在ListBox中添加信息。 * *
*/ public partial class Form1 : Form { private FileWatch FileWatchEventSource; public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; FileWatchEventSource = new FileWatch();
FileWatchEventSource.FileWatchEvent
+= new FileWatchEventHandler(OnFileChange); var thrd = new Thread(new ThreadStart(FileWatchEventSource.MonitorFile)); thrd.Start(); } private void Form1_Load(object sender, EventArgs e) { }
//綁定事件的方法
private void OnFileChange(object Sender, EventArgs e) { listBox1.Items.Add(DateTime.Now.ToString() + ": 文件發生改變."); } } public delegate void FileWatchEventHandler(object sender, EventArgs e); public class FileWatch { private bool _bLastStatus = false; public FileWatch() { // // TODO: 在此處添加構造函數邏輯 // } public event FileWatchEventHandler FileWatchEvent; //調用事件的方法,執行這個方法之后就會執行綁定到當前事件字段上的那個方法 protected virtual void OnFileChangeEvent(EventArgs e) { FileWatchEvent?.Invoke(this, e); } public void MonitorFile() { bool bCurrentStatus; while (true) { bCurrentStatus = File.Exists(@"D:/test.txt"); //狀態不符,說明文件被刪除或重新創建,此時觸發事件; if (bCurrentStatus != _bLastStatus) { _bLastStatus = bCurrentStatus; OnFileChangeEvent(EventArgs.Empty); } Thread.Sleep(1000); } } } }

 

結果:

 

 

 

 

 

3.事件的聲明

事件是基於委托的。

第一層意思:就是說事件需要委托來做約束,這個約束既規定了事件能夠發送什么樣的消息給事件的響應者,也規定了事件的響應者返回什么樣的消息,所以說這個事件的事件響應器必須和這個事件匹配上才能訂閱這個事件。

第二層意思:當事件的響應者給事件的擁有者提供了能夠匹配的事件處理器之后,需要找個地方將事件處理器記錄保存下來,能夠記錄和引用方法的任務也只有委托能夠實現。

總的來說,事件不管是從表層約束來講,還是底層實現來講,都是依賴於委托的。

(1)完整聲明

 比如去餐館吃飯,這時候會有服務員來訂閱你點菜的事件,當點菜的事件發生,服務員之后就會上菜。實際上服務員拿自己的事件處理器來處理你點菜的事件。現在我們聲明實現一個點菜的事件。 

namespace TestClass
{ 
    class Program
    {
        static void Main(string[] args)
        {
            //customer是事件擁有者, 
            Customer customer = new Customer();
            //waitor是事件的響應者
            Waitor waitor = new Waitor();
            //Order是事件,Action是事件處理器
            //訂閱事件
            customer.Order += waitor.Action;
            //訂閱完事件,下面需要執行這個事件
            customer.Action();
            customer.PayTheBill();
            Console.ReadKey(); 
        } 
    }
    /// <summary>
    /// 如果一個委托是為了聲明一個事件准備的,那么需要后綴加上EventHandler
    /// 這個委托和類是平級的,因為委托本質上是類。
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="e"></param>
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
    /// <summary>
    /// 菜單信息類
    /// 如果某個類是作為EventArgs事件參數來使用的話,那就需要繼承EventArgs
    /// </summary>
    public class OrderEventArgs:EventArgs
    {
        /// <summary>
        /// 菜名
        /// </summary>
        public string DishName;
        public string Size;
      
    }
    public class Customer
    {
        /// <summary>
        /// 賬單
        /// </summary>
        public double Bill;
        private OrderEventHandler orderEventHandler;
        /// <summary>
        /// 創建一個事件Order點菜
        /// 這個事件是由OrderEventHandler委托進行約束的。
        /// </summary>
        public event OrderEventHandler Order
        {
            add
            { 
                this.orderEventHandler += value;
            }
            remove
            {
                this.orderEventHandler -= value; 
            }

        }
        public void PayTheBill()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }

        public void WalkIn()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        public void SitDown()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        /// <summary>
        /// 思考吃什么
        /// </summary>
        public void Think()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
             //先判斷有沒有訂閱這個事件
            if(this.orderEventHandler!=null)
            {
                OrderEventArgs orderEventArgs = new OrderEventArgs();
                orderEventArgs.DishName = "Noodles";
                orderEventArgs.Size = "Size";
                this.orderEventHandler(this,orderEventArgs);
            }
        }
        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();
          
        }
    }
    /// <summary>
    /// 服務生
    /// </summary>
    public class Waitor
    {
       public   void Action(Customer customer, OrderEventArgs e)
        {
            Console.Write($"DishName={e.DishName}");
            double price = 10;
            switch(e.Size)
            {
                case "small":
                    price *= 0.5;
                    break;
                case "large":
                    price *= 1.5;
                    break;
                default:
                    break;
            }
            customer.Bill += price;
        }
    } 
}

注意上面的代碼,之所以使用EventHandler后綴,用意有3個:第一個是別人看到后就會知道這個委托是專門用來生成事件的。第二個是說明這個委托是用來約束事件處理器的。第三個是指這個委托將來是專門用來存儲事件處理器的。

簡化聲明:

namespace TestClass
{ 
    class Program
    {
        static void Main(string[] args)
        {
            //customer是事件擁有者, 
            Customer customer = new Customer();
            //waitor是事件的響應者
            Waitor waitor = new Waitor();
            //Order是事件,Action是事件處理器
            //訂閱事件
            customer.Order += waitor.Action;
            //訂閱完事件,下面需要執行這個事件
            customer.Action();
            customer.PayTheBill();
            Console.ReadKey(); 
        } 
    }
    /// <summary>
    /// 如果一個委托是為了聲明一個事件准備的,那么需要后綴加上EventHandler
    /// 這個委托和類是平級的,因為委托本質上是類。
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="e"></param>
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
    /// <summary>
    /// 菜單信息類
    /// 如果某個類是作為EventArgs事件參數來使用的話,那就需要繼承EventArgs
    /// </summary>
    public class OrderEventArgs:EventArgs
    {
        /// <summary>
        /// 菜名
        /// </summary>
        public string DishName;
        public string Size;
      
    }
    public class Customer
    {
        /// <summary>
        /// 賬單
        /// </summary>
        public double Bill;
        /// <summary>
        /// 創建一個事件Order點菜
        /// 這個事件是由OrderEventHandler委托進行約束的。
        /// </summary>
        public event OrderEventHandler Order;
       
        public void PayTheBill()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }

        public void WalkIn()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        public void SitDown()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        /// <summary>
        /// 思考吃什么
        /// </summary>
        public void Think()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
             //先判斷有沒有訂閱這個事件
            if(this.Order != null)
            {
                OrderEventArgs orderEventArgs = new OrderEventArgs();
                orderEventArgs.DishName = "Noodles";
                orderEventArgs.Size = "Size";
                this.Order(this,orderEventArgs);
            }
        }
        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();
          
        }
    }
    /// <summary>
    /// 服務生
    /// </summary>
    public class Waitor
    {
       public   void Action(Customer customer, OrderEventArgs e)
        {
            Console.Write($"DishName={e.DishName}");
            double price = 10;
            switch(e.Size)
            {
                case "small":
                    price *= 0.5;
                    break;
                case "large":
                    price *= 1.5;
                    break;
                default:
                    break;
            }
            customer.Bill += price;
        }
    } 
}

4.有了委托字段/屬性,為什么還需要事件?

為了程序的邏輯更加的‘有道理’,更加安全,防止‘借刀殺人’

比如在餐館中,明明你沒有點別的菜,但是別人給點了,記到了自己上面。

如下:

namespace TestClass
{
    class Program
    {
        static void Main(string[] args)
        {
            //customer是事件擁有者, 
            Customer customer = new Customer();
            //waitor是事件的響應者
            Waitor waitor = new Waitor();
            //Order是事件,Action是事件處理器
            //訂閱事件
            customer.Order += waitor.Action;
            //訂閱完事件,下面需要執行這個事件
            //customer.Action();
            #region  不用事件,使用委托,菜品信息都是外部傳入,沒法保證安全性,使用事件的話,都是在自己的內部類中決定的菜品,給外部只留是否訂閱事件的選項
            OrderEventArgs orderEventArgs = new OrderEventArgs()
            {
                DishName = "test1",
                Size="small"
            };
            OrderEventArgs orderEventArgs1 = new OrderEventArgs()
            {
                DishName = "test2",
                Size = "large"
            };
              
            Customer badCustomer = new Customer();
            badCustomer.Order += waitor.Action;
            badCustomer.Order(customer, orderEventArgs1);
            badCustomer.Order(customer, orderEventArgs);


            #endregion



            customer.PayTheBill();
            Console.ReadKey();
        }
    }
    /// <summary>
    /// 如果一個委托是為了聲明一個事件准備的,那么需要后綴加上EventHandler
    /// 這個委托和類是平級的,因為委托本質上是類。
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="e"></param>
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
    /// <summary>
    /// 菜單信息類
    /// 如果某個類是作為EventArgs事件參數來使用的話,那就需要繼承EventArgs
    /// </summary>
    public class OrderEventArgs : EventArgs
    {
        /// <summary>
        /// 菜名
        /// </summary>
        public string DishName;
        public string Size;

    }
    public class Customer
    {
        /// <summary>
        /// 賬單
        /// </summary>
        public double Bill;
        /// <summary>
        /// 創建一個事件Order點菜
        /// 這個事件是由OrderEventHandler委托進行約束的。
        /// </summary>
        //public event OrderEventHandler Order;
        #region  不用事件,使用委托
        //創建委托字段
        public   OrderEventHandler Order;

        #endregion
        public void PayTheBill()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }

        public void WalkIn()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        public void SitDown()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        /// <summary>
        /// 思考吃什么
        /// </summary>
        public void Think()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
            //先判斷有沒有訂閱這個事件
            if (this.Order != null)
            {
                OrderEventArgs orderEventArgs = new OrderEventArgs();
                orderEventArgs.DishName = "Noodles";
                orderEventArgs.Size = "Size";
//因為事件是從事件擁有者的內部觸發的,
this.Order(this, orderEventArgs); } } public void Action() { Console.ReadLine(); this.WalkIn(); this.SitDown(); this.Think(); } } /// <summary> /// 服務生 /// </summary> public class Waitor { public void Action(Customer customer, OrderEventArgs e) { Console.Write($"DishName={e.DishName}"); double price = 10; switch (e.Size) { case "small": price *= 0.5; break; case "large": price *= 1.5; break; default: break; } customer.Bill += price; } } }

需要注意的是,在開發的時候,很多項目是很多人一起做,如果沒有做限制的話,很可能會被濫用。如果是通過事件的話,就會確保只有訂閱了這個事件的事件響應者才會和這個事件有聯系。事件的觸發只能是事件的擁有者才能觸發,比委托更安全。

把上面代碼中  public event OrderEventHandler Order;這行代碼的event去掉,就會報錯,這種使用有問題(  badCustomer.Order(customer, orderEventArgs1);): 事件“Customer.Order”只能出現在 += 或 -= 的左邊(從類型“Customer”中使用時除外) 。

 5.事件的本質是委托字段的包裝器

(1)這個包裝器對委托字段的訪問起限制作用

(2)封裝的一個重要功能就是隱藏

(3)事件對外界隱藏了委托字段的大部分功能,僅暴露添加/移除事件處理器的功能。(所以上面代碼將委托字段改成事件(加上event)之后就會報錯,事件對於本類的外界來說,只暴露了添加/移除事件處理器的功能)

6.通用的事件約束

下面是一個通用的事件約束 

代碼:

namespace TestClass
{
    class Program
    {
        static void Main(string[] args)
        {
            //customer是事件擁有者, 
            Customer customer = new Customer();
            //waitor是事件的響應者
            Waitor waitor = new Waitor();
            //Order是事件,Action是事件處理器
            //訂閱事件
            customer.Order += waitor.Action;
            //訂閱完事件,下面需要執行這個事件
            customer.Action(); 

            customer.PayTheBill();
            Console.ReadKey();
        }
    }
     
    /// <summary>
    /// 菜單信息類
    /// 如果某個類是作為EventArgs事件參數來使用的話,那就需要繼承EventArgs
    /// </summary>
    public class OrderEventArgs : EventArgs
    {
        /// <summary>
        /// 菜名
        /// </summary>
        public string DishName;
        public string Size;

    }
    public class Customer
    {
        /// <summary>
        /// 賬單
        /// </summary>
        public double Bill;
        /// <summary>
        /// 創建一個事件Order點菜
        /// 這個事件是由EventHandler委托進行約束的。
        /// </summary>
        public event  EventHandler Order;
       
        public void PayTheBill()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }

        public void WalkIn()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        public void SitDown()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        /// <summary>
        /// 思考吃什么
        /// </summary>
        public void Think()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
            //先判斷有沒有訂閱這個事件
            if (this.Order != null)
            {
                OrderEventArgs orderEventArgs = new OrderEventArgs();
                orderEventArgs.DishName = "Noodles";
                orderEventArgs.Size = "Size";
                this.Order(this, orderEventArgs);
            }
        }
        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();

        }
    }
    /// <summary>
    /// 服務生
    /// </summary>
    public class Waitor
    {
        public void Action(object  obj, EventArgs args)
        {
            Customer customer = (Customer)obj;
            OrderEventArgs e = args as OrderEventArgs;
            Console.Write($"DishName={e.DishName}");
            double price = 10;
            switch (e.Size)
            {
                case "small":
                    price *= 0.5;
                    break;
                case "large":
                    price *= 1.5;
                    break;
                default:
                    break;
            }
            customer.Bill += price;
        }
    } 
}

7.觸發事件Foo,一般謝偉OnFoo,而且級別一般是protected級別,防止“借刀殺人”

所以修改后的代碼:

namespace TestClass
{
    class Program
    {
        static void Main(string[] args)
        {
            //customer是事件擁有者, 
            Customer customer = new Customer();
            //waitor是事件的響應者
            Waitor waitor = new Waitor();
            //Order是事件,Action是事件處理器
            //訂閱事件
            customer.Order += waitor.Action;
            //訂閱完事件,下面需要執行這個事件
            customer.Action();  
            customer.PayTheBill();
            Console.ReadKey();
        }
    } 
    /// <summary>
    /// 菜單信息類
    /// 如果某個類是作為EventArgs事件參數來使用的話,那就需要繼承EventArgs
    /// </summary>
    public class OrderEventArgs : EventArgs
    {
        /// <summary>
        /// 菜名
        /// </summary>
        public string DishName;
        public string Size; 
    }
    public class Customer
    {
        /// <summary>
        /// 賬單
        /// </summary>
        public double Bill;
        /// <summary>
        /// 創建一個事件Order點菜
        /// 這個事件是由EventHandler委托進行約束的。
        /// </summary>
        public event  EventHandler Order;
       
        public void PayTheBill()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        } 
        public void WalkIn()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        public void SitDown()
        {
            Console.WriteLine($"支付賬單:{this.Bill}");
        }
        /// <summary>
        /// 思考吃什么
        /// </summary>
        public void Think()
        {
            Console.WriteLine("Thinking");
            this.OnOrder("chicken","large");
        }
        protected void OnOrder(string name,string size)
        {   
            //先判斷有沒有訂閱這個事件
            if (this.Order != null)
            {
                OrderEventArgs orderEventArgs = new OrderEventArgs();
                orderEventArgs.DishName = name;
                orderEventArgs.Size = size;
                this.Order(this, orderEventArgs);
            }
        } 
        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think(); 
        }
    }
    /// <summary>
    /// 服務生
    /// </summary>
    public class Waitor
    {
        public void Action(object  obj, EventArgs args)
        {
            Customer customer = (Customer)obj;
            OrderEventArgs e = args as OrderEventArgs;
            Console.Write($"DishName={e.DishName}");
            double price = 10;
            switch (e.Size)
            {
                case "small":
                    price *= 0.5;
                    break;
                case "large":
                    price *= 1.5;
                    break;
                default:
                    break;
            }
            customer.Bill += price;
        }
    } 
}

8.事件的命名約定

(1)帶有時態的動詞或者動詞短語

(2)正在做什么用進行時,完成做什么就用完成時。

 

 委托是一個類,事件是委托的實例,比如委托是一個Student類,那么事件就是具體的學生張三,李四。

 補充

 為什么要使用事件?

一開始方法的邏輯很多,而且不穩定,想把不穩定的邏輯轉移一下,可以通過事件。 

 案例1:比如貓進食,比如有統一的步驟:有洗爪子,圍餐巾,吃東西,然后洗爪子,打嗝,剔牙。 

   public class Cat
    {
        /// <summary>
        /// 進食--不同的食物
        /// </summary>
        /// <param name="httpContext">食物</param>
        public void Eat(string  httpContext)
        {

            Console.WriteLine("洗爪子1");
            Console.WriteLine("圍餐巾");
            Console.WriteLine($"eating{httpContext}");
            Console.WriteLine("洗爪子2");
            Console.WriteLine("打嗝");
            Console.WriteLine("剔牙"); 
        }
         
    }

 

調用:

  class Program
    { 
        static void Main(string[] args)
        {
            Cat cat = new Cat();
            cat.Eat("貓糧");
            Console.WriteLine("*************************");
            cat.Eat("面包");
            Console.WriteLine("*************************");
        }
         
    }

 

 

但是不同的貓在這些步驟前后可能會做一些不同的事情,除了固定每只貓都有自己的其他習慣,我們不能來一只貓就要改Eat方法,所以我們可以通過事件來解決這個問題。

    public class Cat
    {
        /// <summary>
        /// 進食--不同的食物
        /// </summary>
        /// <param name="httpContext">食物</param>
        public void Eat(string  httpContext)
        { 
            if(CleanHand1Before!=null)
            {
                CleanHand1Before.Invoke();
            } 
            Console.WriteLine("洗爪子1"); 
            if (CleanHand1After != null)
            {
                CleanHand1After.Invoke();
            }

            if (NapkinHand1Before != null)
            {
                NapkinHand1Before.Invoke();
            }
            Console.WriteLine("圍餐巾"); 
            if (NapkinHand1After != null)
            {
                NapkinHand1After.Invoke();
            }
             
            Console.WriteLine($"eating{httpContext}");

            if (CleanHand2Before != null)
            {
                CleanHand2Before.Invoke();
            } 

            Console.WriteLine("洗爪子2");
            if (CleanHand2After != null)
            {
                CleanHand2After.Invoke();
            }

            if (BurpHand1Before != null)
            {
                BurpHand1Before.Invoke();
            }

            Console.WriteLine("打嗝");
            if (BurpHand1After != null)
            {
                BurpHand1After.Invoke();
            }

            if (PickHand1Before != null)
            {
                PickHand1Before.Invoke();
            }

            Console.WriteLine("剔牙");
            if (PickHand1After != null)
            {
                PickHand1After.Invoke();
            }

        }


        #region 步驟之前 
        public event Action CleanHand1Before;
        //圍餐巾
        public event Action NapkinHand1Before;
        public event Action CleanHand2Before;
        //打嗝
        public event Action BurpHand1Before;
        //剔牙
        public event Action PickHand1Before;
        #endregion

        #region 步驟之后

        public event Action CleanHand1After;
        //圍餐巾
        public event Action NapkinHand1After;
        public event Action CleanHand2After;
        //打嗝
        public event Action BurpHand1After;
        //剔牙
        public event Action PickHand1After;
        #endregion


    }

 

調用: 

 

 

 class Program
    {
        static void Main(string[] args)
        {
            Cat cat = new Cat();
            cat.PickHand1Before += () => Console.WriteLine("cat剔牙之前洗臉");
            cat.Eat("貓糧"); 
            Console.WriteLine("*************************");

            Cat cat1 = new Cat();
            cat1.PickHand1Before += () => Console.WriteLine("cat1剔牙之前運動");
            cat1.Eat("魚兒"); 
            Console.WriteLine("*************************");
        }

    } 

 

結果:

洗爪子1
圍餐巾
eating貓糧
洗爪子2
打嗝
cat剔牙之前洗臉
剔牙
*************************
洗爪子1
圍餐巾
eating魚兒
洗爪子2
打嗝
cat1剔牙之前運動
剔牙
*************************

所以,可以根據實際業務情況來自由增加刪除事件,Eat方法也不必每次都做改動。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

引於:https://www.bilibili.com/video/BV13b411b7Ht?p=21 

 


免責聲明!

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



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