在事件/委托中使用Thread.Sleep无果,请指点?

.Net技术 码拜 8年前 (2016-02-22) 1045次浏览
各位好:
最近在学习《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上了。书上也是这么说的。
但是实际运行的结果是:语句会不停的输出,如下
在事件/委托中使用Thread.Sleep无果,请指点?
不知道原因在什么地方?
请指点在事件/委托中使用Thread.Sleep无果,请指点?

解决方案

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 并不会取消未触发的事件。


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明在事件/委托中使用Thread.Sleep无果,请指点?
喜欢 (0)
[1034331897@qq.com]
分享 (0)