zoukankan      html  css  js  c++  java
  • 【C#基础】委托那些事儿(二)

    二、传统的委托

      接下来讲一讲方法参数。下面以“餐馆服务员为客户下单”[2]的事件作为描述。一般对事件的做法分3个部分:

      1. 方法参数 EventArgs,一般用于传送数据。在本例场景中

    public delegate void OrderEventHandler(Customer cus, OrderEventArgs e);
    
    public class OrderEventArgs : EventArgs    // 习惯把xxEventArgs 继承于C#自带的EventArgs
    {
        public string DishName { get; set;}    // 菜名
        public string Size { get; set;}        // 份量
    }

      2 . 触发事件的对象

      // 下单的事件是Customer对象拥有的,∴写在Customer类当中

    public class Customer
    {
        private OrderEventHandler orderEventHandler;
        public event OrderEventHandler Order {              // event类型是用来操作“方法类”这个盒子的
            add { this.orderEventHandler += value;}         // add是事件处理器的添加器
            remove { this.orderEventHandler -= value;}
        }
    
        public void ThinkForOrder ()                        // 顾客下单
        {
             if (this.orderEventHandler != null )
             {  
                   orderEventArgs e = new orderEventArgs{ DishName = "Soup", Size = "Large"};
                   this.orderEventHandler.Invoke(this, e);  // this指此类实例化的customer
             }
        }
    }

      3 . 执行的方法

      在主函数中,为customer对象的Order事件订阅waiter.Action,客户的下单,需要由服务员行动。

      cus.Order += waiter.Action;

      即有:

            public class Waiter

            { public void Action(Customer cus, OrderEventArgs e) { ... }  }

      总结上文:

    Main

           Customer cus = new Customer();

           Waiter wai = new Waiter();

           cus.Order += wai.Action;

           cus.ThinkForOrder();

           Console.WriteLine("the customer will pay {0}.", cus.BillPrice);

    Customer

     

    事件对象对eventHandler方法类的订阅

    Waiter

        public class Waiter

        {

            internal void Action(Customer customer, OrderEventArgs e)       // internal可改为public

            {

                Console.WriteLine("Waiter will serve Mr.{0} {1}." , customer.Name, e.DishName);

                customer.Bill += e.Price;

            }

        }

    三、小结

      如果把事件写成委托型字段的话:

      -  假设有一客人badGuy,并且badGuy.Order += waiter.Action;,那么如果badGuy.Order.Invoke(),即会破坏参数e,或者参数customer。

         例如,badGuy不给自己点菜,点到了customerA上,badGuy.Order.Invoke(customerA, e2);

      

      事件:

      -     使逻辑、对象关系更加安全,防止“借刀杀人”。

      -      只能写在+=或-=的左边。避免了委托被直接invoke调用。

        (委托字段可能在public当中被滥用,所以微软推出Event这种成员。)

      -      本质:委托字段的包装器;

                       对委托字段的访问仅起限制作用,仅暴露add、remove事件处理器的功能。

      -      参数:一个表示发送者,e表示发送的消息/数据/内容

      -      规定:事件触发必须由事件Foo拥有者自己去发送信息。

           触发事件的方法一般命名为:OnFoo,意为事出有因。

        注意:OnFoo的访问级别一定是protected,若为public又可“借刀杀人”了。

      首尾呼应:

      属性不是字段——很多时候,属性是字段的包装器,保护字段不被滥用。包装器永远不可能是包装的东西。

    注释:

    [1] 自《深入理解C#》(第3版)Jon Skeet 著  姚琪琳 译

    [2] 自刘猛铁的C#学习视频

  • 相关阅读:
    【JZOJ4807】破解
    输入挂(更新)
    Gorgeous Sequence(线段树)
    线段树套路系列
    hdu 3333 离线线段树 + 思维/树状数组 /在线主席树
    3183 RMQ / 贪心(坑成。。)
    hdu3594 强连通(仙人掌图)
    hdu3639 强连通
    hdu3861 强连通+最小路径覆盖
    图论--最小树形图朱刘算法模板
  • 原文地址:https://www.cnblogs.com/carmen-019/p/10483683.html
Copyright © 2011-2022 走看看