[C#参考]事件机制
还是那个项目,为了降低程序的耦合性,我决定小小的重构一下自己原来的代码,把Socket通信和帧的分析这两部分分别封装成一个类,当然线程没有变,只是封装了一下,为的就是模块测试完容易拼接。这也是我打算降低耦合度的原因,不然根本没法拼接,好乱好乱。
但是封装Socket通信和数据分析模块就带来了一些问题。现在有两个类:
UI类,负责界面显示和绘制
SocketUtil类,负责通信,抓取数据
所以我在UI类中new了一个SocketUtil类,然后利用这个SocketUtil类实例中的方法通信。
但是这就产生问题了,我需要SocketUtil类实例的一些函数反馈一些实时信息给UI类的某个label(这是的SocketUtil类是不知道UI类存在的,也不能把UI类的实例传给SocketUtil类,因为它是UI类,所以SocketUtil类的函数代码中根本没有任何和UI类相关的东西)。于是想到了C#的事件就能解决这个问题。
下面是我转载的一篇文章,算学习一下,做个笔记:
在所有关于C#事件机制的介绍中,我更倾向于发布者/订阅者(Publisher/Subscriber)这种描述。理解事件机制并不是一件容易的事情,它所涉及的思想值得我们好好去研究。
本文资源来自《C#与.NET技术平台实战演练》——中国青年出版社
谈到事件,我们涉及到两个角色:事件发布者(Publisher)和事件订阅者(Scriber),也可以说是事件发送者(Sender)和事件接收者(Receiver)的关系。举个例子来说,市面上目前有许多杂志,杂志的种类也很多。而我只对其中的某些感兴趣,那么我就可以向杂志发行商提出订阅。之后,每当杂志发行时,我就会收到我在杂志发行商那儿订阅的杂志。在这个关系中,杂志发行商就相当于事件发行者,而我就是事件订阅者。每当杂志发行时,就触发了一个发行事件。
用面向对象的语言解释,这两者的意义如下:
事件发行者(Publisher)
它是一个对象,且会维护自身的状态信息。每当状态信息发生变动时,便触发一个事件,并通知所有的事件订阅者。对于杂志发行商来说,每本杂志都有自己的信息在里面,当杂志发行时,我要通知订阅该杂志的人:杂志已经发行啦,请注意查收!
事件接收者(Receiver)
这个对象要注册它感兴趣的对象,也就是订阅它自己喜欢的杂志啦。另外,这个对象通常要提供一个事件处理方法,在事件发行者触发一个事件后,会自动执行这个方法。对于上面所举的例子来说,也就是我收到杂志后要做什么事情,比如,你可以满世界地大喊:我收到杂志啦!也可以将杂志收藏起来慢慢欣赏,具体怎么实现完全取决你自己的喜好。
以下是.NET事件处理机制的模型:
下面给一个简单的例子,用以阐述事件的思想:
using System.Collections.Generic;
using System.Text; namespace EventDemo
{
public delegate void SalaryCompute(); //声明一个代理类 public class Employee
{
public event SalaryCompute OnSalaryCompute; //定义事件,将其与代理绑定 public virtual void FireEvent() //触发事件的方法
{
if (OnSalaryCompute != null)
{
OnSalaryCompute(); //触发事件
}
}
} public class HumanResource
{
public void SalaryHandler() //事件处理函数
{
Console.WriteLine("Salary"); //只是打印一行字而已
} public static void Main()
{
Employee ep = new Employee();
HumanResource hr = new HumanResource();
ep.OnSalaryCompute+=new SalaryCompute(hr.SalaryHandler); //注册
ep.FireEvent(); //触发事件
Console.Read();
}
}
}
在这个例子中,Employee类相当于一个事件发布者(Publisher),它定义了事件的相关信息,包括定义了一个事件用于计算薪水(OnSalaryCompute),以及一个触发事件的函数(FireEvent()),为简单起见,本例没有加上事件参数。
与之相对应,HumanResource类则相当于一个事件订阅者(Subscriber),它定义了一个事件处理函数(SalaryHandler()),并用+=将其与事件联系起来,从而使事件触发的时候能够调用我这个方法(在本例中也就是打印一行字啦)。值得注意的一点是,事件处理函数的方法签名要与代理的方法签名相同,这是非常重要的一点。
下面将这个例子改造一下,事件参数信息,用以完善事件机制。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace EventDemo
{ public delegate void SalaryCompute(object sender,MyEventArgs e); //声明一个代理类 public class Employee
{
public event SalaryCompute OnSalaryCompute; //定义事件,将其与代理绑定 public virtual void FireEvent(MyEventArgs e) //触发事件的方法
{
if (OnSalaryCompute != null)
{
OnSalaryCompute(this,e); //触发事件
}
}
}//class public class MyEventArgs : EventArgs //定义消息参数类
{
private readonly double salary; //注意属性怎么玩的
public double Salary
{
get { return salary; }
//因为是readonly的,所以只有构造函数可以设置
//set { salary = value; }
} public MyEventArgs(double _salary)
{
this.salary = _salary;
}
}//class public class HumanResource
{
public void SalaryHandler(object sender,MyEventArgs e) //事件处理函数,其签名应与代理签名相同
{
Console.WriteLine("Salary is {0}",e._salary); //只是打印一行字而已
} public static void Main()
{
Employee ep = new Employee();
HumanResource hr = new HumanResource();
MyEventArgs e = new MyEventArgs(123.40);
ep.OnSalaryCompute+=new SalaryCompute(hr.SalaryHandler); //注册
for (; ; )
{
Thread.Sleep(); //让程序“睡”一秒
ep.FireEvent(e); //触发事件
}
}
}//class
}
在这个例子中,我们要注意的一个地方就是事件处理函数的签名要和代理的签名一致。还有要注意的就是:
1. 委托一定要在所有类的外面,在一个namespace中定义,它的本质也是一个类。
2. 事件的定义和触发事件的方法(不是触发事件)要在publisher中定义。
3. 事件的处理函数,要定义在subscriber中
4. 事件的参数,是在同一个namespace中的一个类,是一个参数类。
5. 事件的注册,和事件触发,可以再任何的地方,只要能同时访问两个类的实例。(在publisher或者subscriber中当然算是能访问自己的实例,类似this)
有时间看看这个:http://blog.jobbole.com/36088/
[C#参考]事件机制的更多相关文章
- Atitit 数据库的事件机制--触发器与定时任务attilax总结
Atitit 数据库的事件机制--触发器与定时任务attilax总结 1.1. 事件机制的图谱1 2. 触发器的类型2 3. 实现原理 After触发器 Vs Instead Of触发器2 3.1. ...
- 深入浅出iOS事件机制
原文地址: http://zhoon.github.io/ios/2015/04/12/ios-event.html 本文章将讲解有关iOS事件的传递机制,如有错误或者不同的见解,欢迎留言指出. iO ...
- Javascript事件机制兼容性解决方案
本文的解决方案可以用于Javascript native对象和宿主对象(dom元素),通过以下的方式来绑定和触发事件: 或者 var input = document.getElementsByTag ...
- Atitit.事件机制 与 消息机制的联系与区别
Atitit.事件机制 与 消息机制的联系与区别 1. 消息/事件机制是几乎所有开发语言都有的机制,在某些语言称之为消息(Event),有些地方称之为(Message).1 2. 发布/订阅模式1 3 ...
- 剖析Qt的事件机制原理
版权声明 请尊重原创作品.转载请保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正. QT源码解析(一) QT创建窗口程序.消息循环和WinMai ...
- 百度地图API详解之事件机制,function“闭包”解决for循环和监听器冲突的问题:
原文:百度地图API详解之事件机制,function"闭包"解决for循环和监听器冲突的问题: 百度地图API详解之事件机制 2011年07月26日 星期二 下午 04:06 和D ...
- ApplicationEvent事件机制源码分析
<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...
- Redis源码阅读(一)事件机制
Redis源码阅读(一)事件机制 Redis作为一款NoSQL非关系内存数据库,具有很高的读写性能,且原生支持的数据类型丰富,被广泛的作为缓存.分布式数据库.消息队列等应用.此外Redis还有许多高可 ...
- QT源码之Qt信号槽机制与事件机制的联系
QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...
随机推荐
- BZOJ 1024 SCOI 2009 生日快乐 深搜
题目大意:有一块蛋糕,长为X,宽为Y.如今有n个人来分这块蛋糕,还要保证每一个人分的蛋糕的面积相等.求一种分法,使得全部的蛋糕的长边与短边的比值的最大值最小. 思路:刚拿到这个题并没有什么思路.可是定 ...
- Hadoop学习之编译eclipse插件
近期准备開始学习Hadoop1.2.1的源码,感觉最好的方法还是能够在运行Hadoop及hadoop作业时跟踪调试代码的实际运行情况.因为选择的IDE为eclipse,所以准备编译一下hadoop的e ...
- 依赖注入及AOP简述(十一)——生命周期管理 .
2. 生命周期管理 各种依赖注入框架提供了替开发者管理各种Scope的便利功能,随之而来的就必然是被管理的依赖对象的生命周期管理的问题.所谓生命周期管理,就是一个对象在它所属的Scope中从被 ...
- wamp 虚拟目录的设置(转载)
现在先来配置虚拟主机:1.先打开apache的配置文件httpd.conf,并去掉#Include conf/extra/httpd-vhosts.conf前面的#!!2.打开apache的apach ...
- 关于上次我写的那个ATM程序 ,程序没有什么错,但是有些麻烦,两个类中有好多成员函数重复,因此我把ATM重新写了一边。
不好意思!但是现在这个程序比上次那个好多了,而且没有重复,程序看起来比较简练,以下是新程序: #include<iostream>#include<string>using n ...
- Rectangles
Given two rectangles and the coordinates of two points on the diagonals of each rectangle,you have t ...
- Linux学习之traceroute命令
通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一 ...
- Oracle查看被锁的表和解锁[转]
查看被锁的表 select p.spid,a.serial#, c.object_name,b.session_id,b.oracle_username,b.os_user_name from v$p ...
- js闭包陷阱问题
JavaScript是一种非常强大的函数式编程语言,可以动态创建函数对象. 由于JavaScript还支持闭包(Closure),因此,函数可以引用其作用域外的变量,非常强大. 来看看在JavaScr ...
- ENVI5.1批量镶嵌工具界面按钮显示不全的解决方案
打开批量镶嵌工具,在导出文件界面,部分按钮显示不全.具体见下图: 图 1 界面按钮显示不全 解决方案: 以win7.8系统为例: 显示桌面 – > 右键“个性化” – >显示 – > ...