欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【C#进阶】委托那些事儿(二)

程序员文章站 2022-03-20 10:20:20
二、传统的委托 接下来讲一讲方法参数。下面以“餐馆服务员为客户下单”[2]的事件作为描述。一般对事件的做法分3个部分: 1. 方法参数 EventArgs,一般用于传送数据。在本例场景中 2 . 触发事件的对象 // 下单的事件是Customer对象拥有的,∴写在Customer类当中 3 . 执行 ......

二、传统的委托

  接下来讲一讲方法参数。下面以“餐馆服务员为客户下单”[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(cus, e2);

  

  事件:

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

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

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

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

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

 

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

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

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

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

 

  首尾呼应:

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

 

注释:

[1] 自《深入理解c#》(第3版)jon skeet 著  姚琪琳 译

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