C#委托、事件剖析(下)
本节对事件进行总结。
二、事件:
1、概念:Event:A member that enables an object or class to provide notifications;官方的解释是这样,就是说在C#中,事件是使
对象或者类具备通知能力的成员。比如说手机收到短信提醒我去开会,那么手机就充当了一个具备通知能力的成员。说白了,事件
的作用就是对象和类之间的信息传递的桥梁。
2、原理:源于发生-响应模型:
事件源(event source) + 事件本身(event) => 事件的订阅者(event subscriber) + 事件处理器(event handler)
(另外还有事件的订阅者和事件源之间的订阅关系subscribe relationship)
还是以手机收到短信提醒我去开会为例,事件源:手机吗,事件:收到短信,事件的订阅者:我,事件处理器:去开会,订阅关系:我订阅手机
3、事件的声明:分为详细声明和简略声明:
(1)详细声明:
public delegate void MyDelegateEventHandler();
public class Event
{
private MyDelegateEventHandler myDelegateEventHandler;
public event MyDelegateEventHandler MyDelegate
{
add
{
this.myDelegateEventHandler += value;
}
remove
{
this.myDelegateEventHandler -= value;
}
}
}
(2)简略说明:
public delegate void MyDelegateEventHandler();
public class Event
{
public event MyDelegateEventHandler myDelegate;
}
可以看到,在完整声明中首先添加了一个委托类型的字段,然后暴漏了添加和移除事件处理器的功能,但是我们经常用的是简略声明,因为代码更加简洁,
可以看出事件对外界隐藏了大部分功能,它的本质就是对其中委托字段的一个封装(encapsulation),防止外界偷用滥用委托字段。
那么问题来了:第一个问题:有了委托为什么还会有事件呢,事件内部不就是委托吗,原因是为了防止public型的委托字段在外面被滥用,比如委托可以用invoke调用,
但是事件只能在+=或-=的左侧,这样就增加了整个程序的安全性。
第二个问题:那委托和事件的关系什么样的呢?我们说事件是基于委托的。一方面,事件需要委托来做一个约束,这个约束规定了事件源发送什么要求给事件的订阅者,
事件订阅者的事件处理器必须和这个约束相对应才可以订阅这个事件,另一方面,事件订阅者收到事件以后做出事件处理器,而这个事件处理器必须通过委托才可以做到。
4、简单实例:
Example:做一个窗口,有文本框和按钮,点击按钮文本框显示时间,不用WindowsForms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace ConsoleApp14
{
class Program
{
public static TextBox textBox;
public static Button button;
static void Main(string[] args)
{
Form form = new Form();
TextBox textBox = new TextBox();
Button button = new Button();
form.Controls.Add(textBox);
form.Controls.Add(button);
textBox.Width = ;
button.Top = ;
button.Click += Button_Click;
form.ShowDialog();
} private static void Button_Click(object sender, EventArgs e)
{
textBox.Text = DateTime.Now.ToString();
}
}
}
这里举的事例就是windowsforms内部的代码,我们说事件本身是不会发生的是由事件源内部的逻辑所触发,在本例中,并不是人按了按钮然后按钮触发了事件,
这其中还有一个小过程,就是当按钮被key down再key up时,向程序内部发送了一系列电讯号,通知电脑,然后再发生事件,
5、声明事件的相关约定:
用于声明事件的委托一般用:事件+EvnetHandler,参数一般有2个,第一个事件源,第二个EventArgs的派生类,用于触发事件的方法名一般为On+方法名,
访问级别Protected。可能有点蒙,举个实例就懂了。
Example:举一个顾客在KFC点餐的例子
namespace ConsoleApp15
{
class Program
{
static void Main(string[] args)
{
Customer customer = new Customer();
Waitor waitor = new Waitor();
customer.Order += waitor.Serve;
customer.Eat();
customer.Pay();
}
}
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
public class Customer
{
public int Money { get; set; }
public event OrderEventHandler Order;
public void Pay()
{
Console.WriteLine($"OK,{Money} dollars");
}
public void Eat()
{
Console.WriteLine("Let's go to the KFC...");
Console.WriteLine("Stand in front of the waitor...");
Console.WriteLine("A hamburger,Please...");
OnOrder();
}
protected void OnOrder()
{
OrderEventArgs orderEventArgs = new OrderEventArgs();
orderEventArgs.Snack = "Hamburger";
orderEventArgs.Size = "large";
this.Order.Invoke(this, orderEventArgs); }
}
public class OrderEventArgs : EventArgs
{
public string Snack { get; set; }
public string Size { get; set; }
}
class Waitor
{
public void Serve(Customer customer, OrderEventArgs e)
{
Console.WriteLine($"Here is your snack {e.Snack}");
int price = ;
switch (e.Size)
{
case "large":
price *= ;
break;
case "small":
price *= ;
break;
default:
break;
}
customer.Money += price;
}
}
}
按照事件的五个要素,首先需要事件源,做一个Customer类,还需要一个事件订阅者,做一个Waitor类,然后根据订阅关系去写具体的方法,订阅关系customer.Order += waitor.Serve; Customer点餐Waitor服务,waitor类中上餐并算好价格,这个时候需要一个事件处理器OrderEventHandler,这个委托的参数需要一个OrderEventArgs,创建这个类写好属性,在写好委托和事件,然后在Customer类中写点餐事件,点餐事件为Protected的,和public型的委托字段一样防止被外界滥用,提高安全性。
想融会贯通其实也不难,只需要将事件的5个要素每一个列举出来,那么最后事件也就出来了。
至此事件总结完毕,有不明之处还请指教。 2018-08-17 16:43:19
C#委托、事件剖析(下)的更多相关文章
- Observer设计模式中-委托事件-应用在消息在窗体上显示
Observer设计模式:监视者模式.在类中的方法中处理的结果或者消息通过事件委托 的方式发送给主窗体. 因为在其它类中直接访问主窗体类,显示内容是不能直接调用控件赋值的,当然也有别的类似查阅控件名, ...
- Asp.net用户控件和委托事件
在Asp.net系统制作过程中,门户类型的网站,我们可以用DIV+CSS+JS+Ajax全部搞定,但是一旦遇到界面元素比较复杂的时候,还是UserControl比较方便一些,各种封装,各种处理,然后拖 ...
- c#委托事件及其讲解
一定要标明出处,波哥的文章.所有文章都值得一看.这篇是摘抄的大白话之C#事件讲解.委托 http://www.cnblogs.com/wudiwushen/archive/2010/04/20/170 ...
- JQuery基础教程:事件(下)
事件传播 为了说明不可单击的页面元素处理单击事件的能力,例如样式转换器中包含按钮的div元素或者兄弟元素h3,我们来实现一个鼠标指针进入元素和离开元素时的效果,首先需要添加一种翻转状态,表明 ...
- c#委托事件入门--第二讲:事件入门
上文 c#委托事件入门--第一讲:委托入门 中和大家介绍了委托,学习委托必不可少的就要说下事件.以下思明仍然从事件是什么.为什么用事件.怎么实现事件和总结介绍一下事件 1.事件是什么:. 1.1 NE ...
- Unity C#笔记 委托&事件
C#的委托与事件搭配,即是观察者模式的一种实现. 因为观察者模式的原理很易懂,不作多讲,本文纯粹用于记录语法. delegate(委托) //声明没有参数,没有返回值的委托类型XXXX public ...
- python 全栈开发,Day55(jQuery的位置信息,JS的事件流的概念(重点),事件对象,jQuery的事件绑定和解绑,事件委托(事件代理))
一.jQuery的位置信息 jQuery的位置信息跟JS的client系列.offset系列.scroll系列封装好的一些简便api. 一.宽度和高度 获取宽度 .width() 描述:为匹配的元素集 ...
- Delegate,Action,Func,匿名方法,匿名委托,事件 (转载)
Delegate,Action,Func,匿名方法,匿名委托,事件 (转载) 一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本 ...
- 理解js事件冒泡事件委托事件捕获
js事件冒泡 javascript的事件传播过程中,当事件在一个元素上出发之后,事件会逐级传播给先辈元素,直到document为止,有的浏览器可能到window为止,这就是事件冒泡现象. <di ...
随机推荐
- Java:字符串类简单的正则表达式
class Test { public static void main(String[] args) { String str = "xia..as....yuan.com"; ...
- win C/C++程序通过Get方式获取网页源代码
[转自]http://www.cnblogs.com/coderzh/archive/2008/11/24/1340134.html #include <stdio.h> #include ...
- go语言基础之数组做函数参数是值拷贝
1.数组做函数参数是值拷贝 示例: package main //必须有个main包 import "fmt" //数组做函数参数,它是值传递 //实参数组的每个元素给形参数组拷贝 ...
- Volley框架的介绍使用
Volley是在2013年的Google I/O 2013大会上发布的,是我们的网络通信更快,更简单,更方便.对于初学者来讲是一个很好的框架. 简单来说,它提供了如下的便利功能: JSON,图像等的异 ...
- android 百度地图demo 随感
最近项目组的老大要我对百度的android的sdk进行一段的预研,由于技术太菜,出了不少的错误,因此有一点感悟了. 嗨,这个错误浪费了我一天的时间的时候,我按照百度的技术文档一步步的来做,每部基本上都 ...
- Systemd 三部曲 之 PHP7
安装编译php7时需要的依赖包 : yum -y install libxml2 libxml2-devel openssl openssl-devel curl-devel libjpeg-deve ...
- 转码:gcc在代码中禁止某些warning
http://www.itye.org/archives/3125 gcc 禁止warning 熟悉windows编程的人都知道,禁止编译器输出某个warning,在代码中可以这样 #pragma w ...
- 读取Mat文件中的汉字代码
拿到一种元数据,格式为*.mat,但Access打不开,百度也没看到比较好的解决方案. 但是用文本文档可以打开,那估计它和txt类似了,于是想自己写代码来处理了,立马写了读取的丑陋工具.读取是没什么问 ...
- redis 配置步骤
1.下载 2.启动 3.持久化(快照和AOF) 4.主从配置(集群) 5.读写分离 6.自动切换主从 7.哨兵服务(集群) 8.集群锁 9.Session共享
- JavaScript 之 parseInt
首先还是从很热门的实例parseInt("09")==0说起. parseInt(numString, [radix])这个函数后面如果不跟第2个参数来表示进制的话,默认是10进制 ...