事件的声明
- 完整声明
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { Customer customer = new Customer(); Waiter waiter = new Waiter(); customer.Order += waiter.Action; customer.Action(); customer.PayTheBill(); } } public class OrderEventArgs:EventArgs { public string DishName { get; set; } public string Size { get; set; } } public delegate void OrderEventHandler(Customer customer, OrderEventArgs e); public class Customer { private OrderEventHandler orderEventHandler; public event OrderEventHandler Order { add { this.orderEventHandler += value; } remove { this.orderEventHandler -= value; } } public double Bill { get; set; } public void PayTheBill() { Console.WriteLine("I will pay{0}",this.Bill); } public void Walkin() { Console.WriteLine("Walk into the restaurant."); } public void SitDown() { Console.WriteLine("Sit down."); } public void Think() { for (int i = 0; i < 5; i++) { Console.WriteLine("Let me think..."); } if (this.orderEventHandler != null) { OrderEventArgs e = new OrderEventArgs(); e.DishName = "Kongpao Chicken"; e.Size = "large"; this.orderEventHandler.Invoke(this, e); } } public void Action() { Console.ReadLine(); this.Walkin(); this.SitDown(); this.Think(); } } public class Waiter { public void Action(Customer customer, OrderEventArgs e) { Console.WriteLine("I Will serve you the dish - {0}", e.DishName); double price = 10; switch (e.Size) { case "small": price = price * 0.5; break; case "large": price = price * 1.5; break; default: break; } customer.Bill += price; } } }
- 简略声明(字段式声明,field-like)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { Customer customer = new Customer(); Waiter waiter = new Waiter(); customer.Order += waiter.Action; customer.Action(); customer.PayTheBill(); } } public class OrderEventArgs:EventArgs { public string DishName { get; set; } public string Size { get; set; } } public delegate void OrderEventHandler(Customer customer, OrderEventArgs e); public class Customer { public event OrderEventHandler Order; public double Bill { get; set; } public void PayTheBill() { Console.WriteLine("I will pay{0}",this.Bill); } public void Walkin() { Console.WriteLine("Walk into the restaurant."); } public void SitDown() { Console.WriteLine("Sit down."); } public void Think() { for (int i = 0; i < 5; i++) { Console.WriteLine("Let me think..."); } if (this.Order != null) { OrderEventArgs e = new OrderEventArgs(); e.DishName = "Kongpao Chicken"; e.Size = "large"; this.Order.Invoke(this, e); } } public void Action() { Console.ReadLine(); this.Walkin(); this.SitDown(); this.Think(); } } public class Waiter { public void Action(Customer customer, OrderEventArgs e) { Console.WriteLine("I Will serve you the dish - {0}", e.DishName); double price = 10; switch (e.Size) { case "small": price = price * 0.5; break; case "large": price = price * 1.5; break; default: break; } customer.Bill += price; } } }
有了委托字段/属性,为什么还需要事件?
- 为了程序的逻辑更加“有道理”、更加安全,谨防“借刀杀人”
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { Customer customer = new Customer(); Waiter waiter = new Waiter(); customer.Order += waiter.Action; //customer.Action(); OrderEventArgs e = new OrderEventArgs(); e.DishName = "Manhanquanxi"; e.Size = "large"; OrderEventArgs e2 = new OrderEventArgs(); e2.DishName = "Qingcai"; e2.Size = "large"; Customer badGuy = new Customer(); badGuy.Order += waiter.Action; badGuy.Order.Invoke(customer,e); badGuy.Order.Invoke(customer, e2); customer.PayTheBill(); } } public class OrderEventArgs:EventArgs { public string DishName { get; set; } public string Size { get; set; } } public delegate void OrderEventHandler(Customer customer, OrderEventArgs e); public class Customer { public OrderEventHandler Order; public double Bill { get; set; } public void PayTheBill() { Console.WriteLine("I will pay{0}",this.Bill); } public void Walkin() { Console.WriteLine("Walk into the restaurant."); } public void SitDown() { Console.WriteLine("Sit down."); } public void Think() { for (int i = 0; i < 5; i++) { Console.WriteLine("Let me think..."); } if (this.Order != null) { OrderEventArgs e = new OrderEventArgs(); e.DishName = "Kongpao Chicken"; e.Size = "large"; this.Order.Invoke(this, e); } } public void Action() { Console.ReadLine(); this.Walkin(); this.SitDown(); this.Think(); } } public class Waiter { public void Action(Customer customer, OrderEventArgs e) { Console.WriteLine("I Will serve you the dish - {0}", e.DishName); double price = 10; switch (e.Size) { case "small": price = price * 0.5; break; case "large": price = price * 1.5; break; default: break; } customer.Bill += price; } } }
所以事件的本质是委托字段的一个包装器
- 这个包装器对委托字段的访问起限制作用,相当于一个“蒙板”
- 封装(encapsulation)的一个重要功能就是隐藏
- 事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能
- 添加/移除事件处理器的时候可以直接使用方法名,这是委托实例所不具备的功能
用于声明事件的委托类型的命名约定
- 用于声明Foo事件的委托,一般命名为FooEventHandler(除非是一个非常通用的事件约束)
- FooEventHandler委托的参数一般有两个(由Win32API演化而来,历史悠久)
- 第一个是object类型,名字为sender,实际上就是事件的拥有者、事件的source。
- 第二个是EventArgs类的派生类,类名一般为FooEventArgs,参数名为e。也就是前面讲过的事件参数
- 虽然没有官方的说法,但我们可以把委托的参数列表看做是事件发生后发送给事件响应者的“件消息"
- 触发Foo事件的方法一般命名为OnFoo,即“因何引发”、“事出有因"
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { Customer customer = new Customer(); Waiter waiter = new Waiter(); customer.Order += waiter.Action; customer.Action(); customer.PayTheBill(); } } public class OrderEventArgs:EventArgs { public string DishName { get; set; } public string Size { get; set; } } //public delegate void OrderEventHandler(Customer customer, OrderEventArgs e); public class Customer { public EventHandler Order; public double Bill { get; set; } public void PayTheBill() { Console.WriteLine("I will pay{0}",this.Bill); } public void Walkin() { Console.WriteLine("Walk into the restaurant."); } public void SitDown() { Console.WriteLine("Sit down."); } public void Think() { for (int i = 0; i < 5; i++) { Console.WriteLine("Let me think..."); } this.OnOrder("Kongbaojiding", "large"); } protected void OnOrder(string dishName,string size) { if (this.Order != null) { OrderEventArgs e = new OrderEventArgs(); e.DishName = dishName; e.Size = size; this.Order.Invoke(this, e); } } public void Action() { Console.ReadLine(); this.Walkin(); this.SitDown(); this.Think(); } } public class Waiter { public void Action(object sender, EventArgs e) { Customer customer = sender as Customer; OrderEventArgs orderInfo = e as OrderEventArgs; Console.WriteLine("I Will serve you the dish - {0}", orderInfo.DishName); double price = 10; switch (orderInfo.Size) { case "small": price = price * 0.5; break; case "large": price = price * 1.5; break; default: break; } customer.Bill += price; } } }
- 访问级别为protected,不能为public,不然又成了可以“借刀杀人"了
事件的命名约定
- 带有时态的动词或者动词短语
- 事件拥有者”正在做”什么事情,用进行时;事件拥有者”做完了“什么事情,用完成时