二、传统的委托

  接下来讲一讲方法参数。下面以“餐馆服务员为客户下单”[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#学习视频

【C#进阶】委托那些事儿(二)的更多相关文章

  1. [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门

    [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...

  2. [.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中)

    [.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中) 本节要点: 上节介绍了多线程的基本使用方法和基本应用示例,本节深入介绍.NET ...

  3. [.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能

    [.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能 本节导读: 上节说了缓存是以空间来换取时间的技术,介绍了客户端缓存和两种常用服务器缓布,本节主要介绍一种. ...

  4. JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践

    JAVA进阶之旅(二)--认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践 我们继续聊JAVA,这次比较有意思,那就是反射了 一.认识 ...

  5. 【C#进阶】委托那些事儿(一)

    一.简单的委托 1.1 委托的声明: C#当中,委托(delegate)是一种方法封装,也即委托对象可以作为一种传递方法的变量来使用. 委托也算是一种类,与类是平级的存在.在类中写delegate对象 ...

  6. 解密jQuery事件核心 - 委托设计(二)

    第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...

  7. ES5和ES6那些你必须知道的事儿(二)

    ES5和ES6那些你必须知道的事儿 ES5新增的东西 二.对象方法 1.Object.getPrototypeOf(object) 返回对象的原型 function Pasta(grain, widt ...

  8. Sass进阶之路,之二(进阶篇)

    Sass之二(进阶篇) 1. 数据类型 1.1 Number 数字类型,小数类型,带有像素单位的数字类型,全部都属于Number类型 Number类型详情请点击这里,下面是小例子 1.$n1: 1.2 ...

  9. C#进阶之路(二):事件

    一.初步了解事件 事件是委托的一个子集,为了满足“广播/订阅”模式的需求而生. 事件就是限制委托字段的包装器.限制外界对委托字段内部的访问.相当于封装. 事件就是能够发生的什么事情,主要有以下5个主体 ...

随机推荐

  1. JDK-8不是有效的Win32应用程序

  2. 37. Sudoku Solver (Array;Back-Track)

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

  3. Majority Element(ARRAY-BINARY SEARCH)

    QUESTION Given an array of size n, find the majority element. The majority element is the element th ...

  4. [leetcode]438. Find All Anagrams in a String找出所有变位词

    Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings ...

  5. mybatis框架入门程序:演示通过mybatis实现数据库的查询操作

    我们现在工程基于的数据库见“https://www.cnblogs.com/wyhluckdog/p/10147754.html”这篇博文. 1.mybatis下载 mybatis的代码由githua ...

  6. css样式: 宽高按一定比例进行自适应

    纯 CSS 实现高度与宽度成比例的效果 最近在做一个产品列表页面,布局如右图所示.页面中有若干个 item,其中每个 item 都向左浮动,并包含在自适应浏览器窗口宽度的父元素中. item 元素的 ...

  7. 主成分_CPA

    基本原理:方差最大原理 通过正交变换将原相关性变量转化为不相关的变量 第一主成分:线性组合  方差最大 第二主成分:线性组合,COV(F1,F2)=0 步骤: 原始数据标准化:DataAdjust(m ...

  8. 连接数据库-stone

    # -*- coding:utf-8 -*- import pymysql class mysql: def __init__(self, host, port, dbuser, dbpwd, dbn ...

  9. MySQL的left on 【zt】

    MySQL的left on [zt] (2008-11-03 17:27:30) 转载▼ 标签:  it 分类: 学习笔记 MySQL多表连接查询Left Join,Right Join php开源嘛 ...

  10. C++加速程序的全局执行函数

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); C++的cin和cout在输入输出时,会先 ...