谈到event,就不能不先说一下callback和delegate
如果你使用过C的话,你应该知道有一个函数叫qsort,是用来给数组排序的。但这个函数显然不能承担广泛意义上的比较,因此你需要传递一个指针,他指向具有比较功能的函数。qsort在每次要比较数组元素时都要调用这个函数。这就是callback的概念,在.Net里也可以实现回调,方法是创建一个接口,实现他,传递一个实现此接口的对象的引用。delegate呢,你可以将他理解成一个安全的函数指针。
Notifications跟callback有点类似,但比简单的回调要复杂的多。callback意味着要调用的callback方法被调用的同时要调用的建立callback的方法。这是一个很紧密的耦合。而Notification则要松散一些,你可以注册将来某段时间会或者不会发生的Notification,只当他们发生时处理,否则不用。
你也许想让你写的组件当一些事情发生时通知其他组件,例如,你想写一个按钮组件,当你Click的时候你可能想通知其他组件,而其他组件将不得不准备向你请求Notification,你就要提供一个方法告诉他们你已经有一个可用的Notification。另一方面,你可能也是当其它组件的一些事情发生时希望被通知的人。这时你就需要找到那个特定组件可以提供什么Notification。
在.Net中event是一个你用来广播、引发、处理Notification的机制。大致是这样的,可以引发事件的组件声明这一事件。而希望处理某一特定组件的某一特定事件的组件通过传递一个方法的delegate向引发事件的组件注册。这样,当事件发生时引发事件的组件就会调用每个已注册的方法。通过delegate和event我们可以实现异步调用的功能。在C#中是这样声明一个代理的:public delegate void LogHandler(String message);代理在处理这种回调时已经是很强大了。但是当我们需要代理被存储以便以后的Notification,就有一点麻烦了。比如说我们有一个对象Button,有一个Click事件。我们可以声明一个ClickHandler 的代理类型用于处理Click事件,在我们的Button的Class中声明一个ClickHandler的public实例,这样其他组件希望Click发生时被通知,就可以简单的把他的代理加到Click代理中去。myButton.Click += new ClickHandler(MyMethod);
看上去着好像没什么问题。但是这里却存在一个大问题,我们声明Click代理是public,这违反了我们以前说过的data fields永远不要声明成public,这会有一系列麻烦。解决的办法是声明成private或protected,然后用属性解决读写。这样我们可以private声明Click,在写一对public方法去增加一个listener及减少一个listener。当然在.Net中,当你声明一个event时,.Net已经为你做好这一切了。声明一个事件:
class AlarmTimer {
public event EventHandler Alarm;
// ...
}
这段代码说明AlarmTimer可以向所有其它对象广播它可以引发一个叫Alarm的事件。Alarm事件用的是EventHandler代理类型。EventHandler:无返回值、接受两个参数(Object:指向事件的发送者,EventArgs:包含关于事件的数据)
看一个例子:
class AlarmTimer {
public event EventHandler Alarm;
private Timer myTimer;
public AlarmTimer() {
myTimer = new Timer();
myTimer.Tick += new EventHandler(OnTick);
}
public void Set(Double seconds) {
myTimer.Interval = (Int32)(seconds * 1000);
myTimer.Start();
}
protected void OnTick(Object sender, EventArgs e) {
myTimer.Stop();
if (Alarm != null) Alarm(this, EventArgs.Empty);
}
public void ReEnable() {
myTimer.Enabled = true;
}
}
注意AlarmTimer既引发事件(Alarm)又处理事件(Timer中的Tick事件)
static AlarmTimer myAlarm = new AlarmTimer();
public static void TestEvent() {
myAlarm.Alarm += new EventHandler(TimerEventProcessor);
myAlarm.Set(2);
Console.WriteLine("Timer is set; alarm will go off in two seconds");
Application.Run();
}
//处理事件
private static void TimerEventProcessor(
Object myObject, EventArgs myEventArgs) {
if (MessageBox.Show("Wake up! Continue ringing?",
"Count is: " + alarmCounter,
MessageBox.YesNo) == DialogResult.Yes) {
alarmCounter += 1;
myAlarm.ReEnable();
}
else {
Application.Exit();
}
}
注意:Object和EventArgs不是必需的参数,只是这是一个好的写法模式而已
关于event还有好多没有说,留着以后慢慢说吧。
.Net边学边讲(三)
时间: 2024-09-16 20:02:24
.Net边学边讲(三)的相关文章
新手学Linux(三)----使用 Vagrant 打造跨平台开发环境(二)
前言 安装步骤 工具以及环境介绍 第一步VirtualBox和vagrant的安装 第二步使用vagrant添加虚拟机镜像 1从互联网添加虚拟机镜像文件 2从本地添加镜像文件 第三步初始化虚拟机 第四步使用虚拟机 常用命令 前言 在上一篇<新手学Linux(二)--使用 Vagrant 打造跨平台开发环境(一)>文章中,给大家介绍了什么是vagrant?,vagrant能干什么,以及vagrant的主要使用者,那么今天就给大家讲讲vagrant的具体使用
从零开始学Xamarin.Forms(三) Android 制作启动画面
原文:从零开始学Xamarin.Forms(三) Android 制作启动画面 Xamarin.Forms 在启动的时候相当慢,必须添加一个启动界面,步骤如下: 1.将启动画面的图片命名为:splash_screen.png,并拷贝到 Resources 文件夹下的相应 Drawable 文件夹中: 2.在其中的 Drawable 文件夹下创建 splashscreen.xml ,内容为: <?xml version="1.0" encoding="ut
[老老实实学WCF] 第三篇 在IIS中寄存服务
原文:[老老实实学WCF] 第三篇 在IIS中寄存服务 老老实实学WCF 第三篇 在IIS中寄宿服务 通过前两篇的学习,我们了解了如何搭建一个最简单的WCF通信模型,包括定义和实现服务协定.配置服务.寄宿服务.通过添加服务引用的方式配置客户端并访问服务.我们对WCF的编程生命周期有了一个最基本的了解. 在前两篇中演示的例子,一定要力求背着做下来,包括源程序.配置文件都要背着一行行的手写下来,这样才能有深刻的体会.WCF的知识零散复杂,必须扎扎实实的学习和练习.如果你还没有做到了然于胸,现
10天学安卓-第三天
原文:10天学安卓-第三天 经过第二天的学习,我们正确的调用了百度天气API,将天气信息显示到了界面上,做到这一步,我们的工作就算是完成1%了,剩下99%的工作就需要不断的润色这个未成形的APP了. 最首要的就是,我们要把那么一大堆字符转换为普通用户可以轻松理解的界面,那么我们来学习一下Android里面的界面布局. 打开res/layout/activity_main.xml文件,切换到Layouts选项卡,可以看到里面有许多项目,GridLayout.LinearLayout.Relativ
跟我学XSL(三)
XSL模板与匹配模式 经过前几日的学习,我们学习了XHTML文档的编写和以及三个XSL元素,已能编写相当灵活的XSL文档,今天将学习的是XSL模板的编写.我们都知道,短的文档.程序十分好读,但当规模增大后,其复杂性也以更快的速度增加. 前面我们学了< xsl:for-each >.< xsl:value-of >等,可以用它们对XML数据实现简单的格式化输出,但如果遇到比较复杂的XML格式输出,将XSL按照要求依次写下来的话,一是设计困难,可扩展性
一步一步学EJB3.0(三):悟透会话Bean(下)
三.无状态会话Bean实例 在上一篇文章里,其实我们已经应用到了无状态会话Bean,那好,下面我们详细的来分析下上一篇文 章里给出的示例程序. 没有阅读过的朋友请点击这里阅读:<<一步一步学EJB 3.0(二):初探企业 EJB模块开发>> . 首先我们来看看接口的定义: 1 /** 2 * 远程接口 3 * @author Beniao 4 */ 5 @Remote 6 public interface HelloRemote { 7 void sayHello(String s
跟我学Nodejs(三)--- Node.js模块_javascript技巧
简介及资料 通过Node.js的官方API可以看到Node.js本身提供了很多核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,可以require('模块名')去获取:核心模块具有最高的加载优先级(有模块与核心模块同名时会体现) (本次主要说自定义模块) Node.js还有一类模块为文件模块,可以是JavaScript代码文件(.js作为文件后缀).也可以是JSON格式文本文件(.json作为文件后缀).还可以是编辑过的C/C++文
菜鸟学自动化测试(三)----selenium 命令
关于,selenium 命令这一部分,为了便于像我一样的菜鸟理解,我采用通过例子讲命令的方式.边学边总结吧!相互学习.呵呵. 菜鸟Selenium 命令通常被称为selenese,有一系列运行测试案例所需的命令构成. ----// Actions ----// Actions Actions描述了用户所会作出的操作. Action 有两种形式: action和actionAndWait, action会立即执行,而actionAndWait会假设需要较长时间才能得到该action的相
新手学JAVA(三)----StringBuilder类
上一篇文章新手学JAVA(二)----String类与StringBuffer类的区别中了解到,String的值是不可变的,这就导致 每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间,StringBuffer是可变 类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象. StringBuffer类和StringBuilder类功能基本相似.算是两个双胞胎. 下面主要说两点 第一点 线程安全 Str