写本文的目的是推荐一篇比较好的文章,同时整理出可以在VS2012上实际运行可应用的代码,深入理解C sharp语言里的委托和事件的时间编程技巧和概念,概念的理解有助于编程和看懂代码,通过编写的实例,可以帮助在以后的编程中实际使用到 C sharp的委托和事件,现在的自动化控制项目中的设备管理和参数设置应用到XML-RPC协议,就应用到委托和事件的编程,服务器调用客户端设备的方法以及参数,通知所有设备客户端上传参数。
关键概念:
(1)、在定义事件的那个类A里面,可以任意的使用事件名,可以触发;在别的类里面,事件名只能出现在 += 或 -= 的左边来指向函数,即只能实例化,不能直接用事件名触发。但是可以通过A类的对象来调用A类中的触发事件的函数。这是唯一触发事件的方式。
(2)、不管是多播委托还是单播委托,在没有特殊处理的情况下,在一个线程的执行过程中去调用委托(委托对象所指向的函数),调用委托的执行是不会新起线程的,这个执行还是在原线程中的,这个对于事件也是一样的。当然,如果是在委托所指向的函数里面去启动一个新的线程那就是另外一回事了。
(3)、事件是针对某一个具体的对象的,一般在该对象的所属类A中写好事件,并且写好触发事件的方法,那么这个类A就是事件的发布者,然后在别的类B里面定义A的对象,并去初始化该对象的事件,让事件指向B类中的某一个具体的方法,B类就是A类事件的订阅者。当通过A类的对象来触发A类的事件的时候(只能A类的对象来触发A类的事件,别的类的对象不能触发A类的事件,只能订阅A类的事件,即实例化A类的事件),作为订阅者的B类会接收A类触发的事件,从而使得订阅函数被执行。一个发布者可以有多个订阅者,当发布者发送事件的时候,所有的订阅者都将接收到事件,从而执行订阅函数,但是即使是有多个订阅者也是单线程。
代码(实例代码在VS2012 控制台上调试通过):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace delegate_event_example
{
public class TimeInfoEventArgs : EventArgs
{
public TimeInfoEventArgs(int hour, int minute, int second)
{
this.hour = hour;
this.minute = minute;
this.second = second;
}
public readonly int hour;
public readonly int minute;
public readonly int second;
}
// 定义名为SecondChangeHandler的委托,封装不返回值的方法,
// 该方法带参数,一个clock类型对象参数,一个TimeInfoEventArgs类型对象
public delegate void SecondChangeHandler(object clock, TimeInfoEventArgs timeInformation);
// 被其他类观察的钟(Clock)类,该类发布一个事件:SecondChange。观察该类的类订阅了该事件。
public class Clock
{
// 代表小时,分钟,秒的私有变量
int _hour;
public int Hour
{
get { return _hour; }
set { _hour = value; }
}
private int _minute;
public int Minute
{
get { return _minute; }
set { _minute = value; }
}
private int _second;
public int Second
{
get { return _second; }
set { _second = value; }
}
// 要发布的事件
public event SecondChangeHandler SecondChange;
// 触发事件的方法
protected void OnSecondChange(object clock, TimeInfoEventArgs timeInformation)
{
// Check if there are any Subscribers
if (SecondChange != null)
{
// Call the Event
SecondChange(clock, timeInformation);
}
}
// 让钟(Clock)跑起来,每隔一秒钟触发一次事件
public void Run()
{
for (; ; )
{
// 让线程Sleep一秒钟
Thread.Sleep(1000);
// 获取当前时间
System.DateTime dt = System.DateTime.Now;
// 如果秒钟变化了通知订阅者
if (dt.Second != _second)
{
// 创造TimeInfoEventArgs类型对象,传给订阅者
TimeInfoEventArgs timeInformation = new TimeInfoEventArgs(dt.Hour, dt.Minute, dt.Second);
// 通知订阅者
OnSecondChange(this, timeInformation);
}
// 更新状态信息
_second = dt.Second;
_minute = dt.Minute;
_hour = dt.Hour;
}
}
}
// 一个订阅者。DisplayClock订阅了clock类的事件。它的工作是显示当前时间。
public class DisplayClock
{
// 传入一个clock对象,订阅其SecondChangeHandler事件
public void Subscribe(Clock theClock)
{
theClock.SecondChange += new SecondChangeHandler(TimeHasChanged);
}
// 实现了委托匹配类型的方法
public void TimeHasChanged(object theClock, TimeInfoEventArgs ti)
{
Console.WriteLine("Current Time: {0}:{1}:{2}", ti.hour.ToString(),ti.minute.ToString(), ti.second.ToString());
}
}
// 第二个订阅者,他的工作是把当前时间写入一个文件
public class LogClock
{
public void Subscribe(Clock theClock)
{
theClock.SecondChange += new SecondChangeHandler(WriteLogEntry);
}
// 这个方法本来应该是把信息写入一个文件中
// 这里我们用把信息输出控制台代替
public void WriteLogEntry(object theClock, TimeInfoEventArgs ti)
{
Clock a = (Clock)theClock;
Console.WriteLine("Logging to file: {0}:{1}:{2}", a.Hour.ToString(), a.Minute.ToString(), a.Second.ToString());
}
}
class Program
{
static void Main(string[] args)
{
// 创建clock实例
Clock theClock = new Clock();
// 创建一个DisplayClock实例,让其订阅上面创建的clock的事件
DisplayClock dc = new DisplayClock();
dc.Subscribe(theClock);
// 创建一个LogClock实例,让其订阅上面创建的clock的事件
LogClock lc = new LogClock();
lc.Subscribe(theClock);
// 让钟跑起来
theClock.Run();
}
}
}
借鉴的文档连接是:http://blog.csdn.net/zwj7612356/article/details/8272520