事件例子


因为这个例子太长了,不看的时候往下翻着麻烦,所以单独放进一篇笔记里

class Program
{
	static void Main(string[] args)
	{
		
		Waiter waiter = new Waiter();
		
		Customer Zhangsan = new Customer() { Name = "张三" };
		Zhangsan.GoToRestaurant();
		// 张三叫服务员点餐
		Zhangsan.CallWaiter(waiter);
		Zhangsan.OrderDish();
		// 张三结账
		Zhangsan.PayTheBill(waiter);
		
		
		Customer LiSi = new Customer() { Name = "李四" };
		LiSi.GoToRestaurant();
		// 李四叫服务员点餐
		LiSi.CallWaiter(waiter);
		LiSi.OrderDish();
		LiSi.Pay += waiter.ShowTheBill;
		// 事件只能出现在 += 和 -= 的左边,不能出现在任何其他操作符的左边
		// 且只能在事件拥有者的内部去触发事件
		// 但由于Pay不是事件是委托,所以可以在外部invoke
		// 导致李四把账记张三头上
		LiSi.Pay.Invoke(Zhangsan);
	}
}

class OrderEventArgs : EventArgs
{
    public string DishName { get; set; }
    public string Size { get; set; }
}


delegate void CallWaiterEventHandler(Customer customer);
delegate void PayEventHandler(Customer customer);

// 菜单
enum DishMenu
{
    饺子 = 1,
    面条,
    炒饼,
    盖浇饭,
};

/// <summary>
/// 顾客,喊服务员、点餐、结账事件的拥有者
/// </summary>
class Customer
{
    // 顾客姓名
    public string Name { get; set; }

    // 声明委托类型字段,用来存储引用事件处理器
    private CallWaiterEventHandler _callWaiter;
    // 顾客叫服务员事件——完整声明
    public event CallWaiterEventHandler CallWaiterEvent
    {
        add
        {
            _callWaiter += value;
        }
        remove
        {
            _callWaiter -= value;
        }
    }

    // 顾客点餐事件——简略声明
    public event EventHandler<OrderEventArgs> Order;


    // 顾客付款用委托来做,没有用 event 约束,导致外界可以直接invoke
    public PayEventHandler Pay;


    /// <summary>
    /// 顾客去饭馆吃饭
    /// </summary>
    public void GoToRestaurant()
    {
        Console.WriteLine($"{Name} 走进饭馆...");
        Console.WriteLine();
    }

    /// <summary>
    /// 顾客叫服务员点餐
    /// </summary>
    /// <param name="waiter">服务员对象</param>
    public void CallWaiter(Waiter waiter)
    {
        // 喊服务员点餐, 即服务员订阅顾客的 喊服务员事件和点餐事件
        // 顾客是事件的拥有者,服务员是事件的订阅者
        _callWaiter += waiter.ShowMenu;
        Order += waiter.Serve;

        // 如果有服务员过来了,则触发顾客叫服务员事件,服务员展示菜单
        if (_callWaiter != null)
        {
            _callWaiter.Invoke(this);
            // 顾客思考吃啥
            Thinking();
        }
    }

	// 顾客思考吃啥
    private void Thinking()
    {
        Console.WriteLine($"{Name}:");
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("\t我想想吃啥...");
            Thread.Sleep(1000);
        }
    }

	 /// <summary>
	 /// 顾客点餐
	 /// </summary>
    public void OrderDish()
    {
        // 如果有服务员订阅了点餐事件
        // 即服务员正在等待顾客点餐, 则开始点餐
        if (Order != null)
        {
            Console.WriteLine("我要吃(输入数字):");
            int dishChoice = int.Parse(Console.ReadLine());
            DishMenu dish = (DishMenu)dishChoice;

            Console.WriteLine("份量是(小份/大份):");
            int sizeChoice = int.Parse(Console.ReadLine());
            string size = (sizeChoice == 0) ? "大份" : "小份";

            // 触发顾客点餐事件
            TriggerOrderDish(dish.ToString(), size);
        }
    }

    // 触发顾客点餐事件的代码
    private void TriggerOrderDish(string dishName, string size)
    {
        Order?.Invoke(this, new OrderEventArgs() { DishName = dishName, Size = size });
    }

	/// <summary>
	/// 顾客结账
	/// </summary>
	/// <param name="waiter">服务员对象</param>
	public void PayTheBill(Waiter waiter)
	{
	    // 服务员订阅 + 触发顾客付款事件
	    Pay += waiter.ShowTheBill;
	    Pay?.Invoke(this);
	}
}


/// <summary>
/// 服务员,喊服务员、点餐、结账事件的订阅者
/// </summary>
class Waiter
{
    // 外界只能获取账单,不能修改
    public double Bill { get; private set; }
    private Customer _customer;
    private OrderEventArgs _orderArgs;

    /// <summary>
    /// 喊服务员事件的事件处理器,向顾客展示菜单
    /// </summary>
    public void ShowMenu(object source)
    {
        Customer _customer = source as Customer;

        Console.WriteLine($"欢迎光临,{_customer.Name}先生!这是我们的菜单:");
        Console.WriteLine("1 --- 饺子\t--- 大份 15 元,小份 12 元");
        Console.WriteLine("2 --- 面条\t--- 大份 10 元,小份 7 元");
        Console.WriteLine("3 --- 炒饼\t--- 大份 10 元,小份 7 元");
        Console.WriteLine("4 --- 盖浇饭\t--- 大份 12 元,小份 9 元");
        Console.WriteLine("");
        Console.WriteLine("0 --- 大份");
        Console.WriteLine("其他数字 --- 小份");
        Console.WriteLine("输入数字进行选择,按回车确认。");
        Console.WriteLine("------------------");
    }

    /// <summary>
	/// 点餐事件的事件处理器,向顾客上菜
	/// </summary>
	/// <param name="source">顾客对象</param>
	/// <param name="e">顾客点餐事件参数</param>
    public void Serve(object source, EventArgs e)
    {
        _customer = source as Customer;
        _orderArgs = e as OrderEventArgs;

        Console.WriteLine($"您好,{_customer.Name}先生,这是您点的 {_orderArgs.Size} {_orderArgs.DishName}。");
    }

    // 计算账单
    private void CalculateBill()
    {
        // 先默认是大份
        switch (_orderArgs.DishName)
        {
            case "饺子":
                Bill = 15.0;
                break;
            case "面条":
                Bill = 10.0;
                break;
            case "炒饼":
                Bill = 10.0;
                break;
            case "盖浇饭":
                Bill = 12.0;
                break;
            default:
                break;
        }

        // 如果点的小份便宜3块钱
        switch (_orderArgs.Size)
        {
            case "小份":
                Bill -= 3;
                break;
            default:
                break;
        }
    }

    /// <summary>
	/// 结账事件的事件处理器,向顾客展示账单
	/// </summary>
	/// <param name="source">顾客对象</param>
    public void ShowTheBill(Object source)
    {
        _customer = source as Customer;
        CalculateBill();
        Console.WriteLine($"\n{_customer.Name} 先生,您一共消费了 {Bill} 元.\n");
    }
}


事件借刀杀人例子