各位好:
最近在学习《C#2010图解教程》中的“事件”一章,并照着敲了一遍代码。
但是得到的结果和书中的结果不一样。
先看代码:大体的框架很简单,就是生成一个我们自定义的事件MyElapsed,利用system.timers.timer中的公共事件Elapsed计时器,把触发自定义事件MyElapsed的私有方法OnOneSecond注册到公共事件Elapsed计时器上,这样我们自定义的事件MyElapsed也可以定时被触发。然后再把两个方法注册到MyElapsed上,实现定时输出。
最近在学习《C#2010图解教程》中的“事件”一章,并照着敲了一遍代码。
但是得到的结果和书中的结果不一样。
先看代码:大体的框架很简单,就是生成一个我们自定义的事件MyElapsed,利用system.timers.timer中的公共事件Elapsed计时器,把触发自定义事件MyElapsed的私有方法OnOneSecond注册到公共事件Elapsed计时器上,这样我们自定义的事件MyElapsed也可以定时被触发。然后再把两个方法注册到MyElapsed上,实现定时输出。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace EventSample1 { public class MyTimerClass //声明自定义类 { public event EventHandler MyElapsed; //声明自定义的事件 //定义事件的触发代码 private void OnOneSecond(object source, EventArgs args) { if(MyElapsed != null) MyElapsed(source, args); //触发事件 } //-- private System.Timers.Timer MyPrivateTimer; //声明一个私有计时器 //构造函数 public MyTimerClass() { MyPrivateTimer = new System.Timers.Timer(); //实例化计时器 MyPrivateTimer.Elapsed += OnOneSecond; //将触发事件的私有方法注册到计时器的公共事件上 //设置公共事件的属性 MyPrivateTimer.Interval = 1000; MyPrivateTimer.Enabled = true; } } //提供订阅在自定义事件上的处理程序 class classA { public void TimerHandlerA(object source, EventArgs args) { Console.WriteLine("class A handler called!"); } } class classB { public static void TimerHandlerB(object source, EventArgs args) { Console.WriteLine("class B handler called!"); } } //主程序 class Program { static void Main() { classA ca = new classA(); MyTimerClass mc = new MyTimerClass(); //-- mc.MyElapsed += ca.TimerHandlerA; mc.MyElapsed += classB.TimerHandlerB; //-- Thread.Sleep(2250); Console.ReadLine(); } } }
按照我们的理解,在线程sleep的2秒多时间内,MyElapsed事件会被触发2次,因此应该输出共4句语句后便停止在readline上了。书上也是这么说的。
但是实际运行的结果是:语句会不停的输出,如下:
不知道原因在什么地方?
请指点
解决方案
40
using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; namespace ConsoleApplication1 { public class MyTimerClass //声明自定义类 { public event EventHandler MyElapsed; //声明自定义的事件 //定义事件的触发代码 private void OnOneSecond(object source, EventArgs args) { if (MyElapsed != null) MyElapsed(source, args); //触发事件 } //-- private System.Timers.Timer MyPrivateTimer; //声明一个私有计时器 //构造函数 public MyTimerClass() { MyPrivateTimer = new System.Timers.Timer(); //实例化计时器 MyPrivateTimer.Elapsed += OnOneSecond; //将触发事件的私有方法注册到计时器的公共事件上 //设置公共事件的属性 MyPrivateTimer.Interval = 1000; MyPrivateTimer.Enabled = true; } } //提供订阅在自定义事件上的处理程序 class classA { public void TimerHandlerA(object source, EventArgs args) { Console.WriteLine("{0} class A handler called! at thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId); } } class classB { public static void TimerHandlerB(object source, EventArgs args) { Console.WriteLine("{0} class B handler called! at thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId); } } //主程序 class Program { static void Main() { Console.WriteLine("主线程 {0}", Thread.CurrentThread.ManagedThreadId); classA ca = new classA(); MyTimerClass mc = new MyTimerClass(); //-- mc.MyElapsed += ca.TimerHandlerA; mc.MyElapsed += classB.TimerHandlerB; //-- Thread.Sleep(2250); Console.ReadLine(); } } }
这是 System.Windows.Form.Timer、System.Timers.Timer、System.Threading.Timer 的区别。第二个实际上是简单封装了第三个,所以有许多人建议不要使用第二个,而只使用第一个和第三个。
第一个,总是在主线程上处理 Staop、Start、触发事件,因此假设你计划在事件触发2次之后就 Stop 它,那么它就能精确地只触发两次,原因是 Stop 可以取消未触发的事件。而后边两个是纯粹子线程上注册事件,假设你执行了 Stop,也并不保证仅准确触发2次事件,有可能触发3次(也就是比预想的触发次数多),原因是 Stop 并不会取消未触发的事件。