【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(cus, e2);
事件:
- 使逻辑、对象关系更加安全,防止“借刀杀人”。
- 只能写在+=或-=的左边。避免了委托被直接invoke调用。
(委托字段可能在public当中被滥用,所以微软推出event这种成员。)
- 本质:委托字段的包装器;
对委托字段的访问仅起限制作用,仅暴露add、remove事件处理器的功能。
- 参数:一个表示发送者,e表示发送的消息/数据/内容
- 规定:事件触发必须由事件foo拥有者自己去发送信息。
触发事件的方法一般命名为:onfoo,意为事出有因。
注意:onfoo的访问级别一定是protected,若为public又可“借刀杀人”了。
首尾呼应:
属性不是字段——很多时候,属性是字段的包装器,保护字段不被滥用。包装器永远不可能是包装的东西。
注释:
[1] 自《深入理解c#》(第3版)jon skeet 著 姚琪琳 译
[2] 自刘猛铁的c#学习视频
上一篇: C#NULL条件运算符
下一篇: 发展平台经济 流通创新带动产业升级