代码之家  ›  专栏  ›  技术社区  ›  Nathan

立即启动.net System.Timers.Timer

  •  16
  • Nathan  · 技术社区  · 14 年前

    我使用一个计时器来运行一个相当长的时间间隔(2分钟)定期事件。这很有效。但是,我希望事件在创建计时器时立即触发(而不是等待2分钟)。

    请注意,我不能仅仅通过调用方法来实现这一点,因为它需要一些时间来运行,并且会阻塞应用程序。我需要计时器正常启动,并在单独的线程中运行事件。

    目前我能想到的最好的方法是对计时器进行子类化并创建一个 TriggerManually 方法可以执行以下操作:

    • 关闭自动复位
    • 将间隔设置为1ms

    这将立即触发已用事件,我可以将所有设置恢复正常。

    3 回复  |  直到 14 年前
        1
  •  4
  •   Gishu    14 年前

    你能改用System.Threading.Timer吗? http://msdn.microsoft.com/en-us/library/2x96zfy7.aspx

        2
  •  19
  •   Rob Cooke    14 年前

    你不能手动调用你的事件处理程序吗?

    即使您希望它在线程池线程上执行,也可以调用它。

    class Blah
    {
        private Timer mTimer;
    
        public Blah()
        {
            mTimer = new Timer(120000);
    
            ElapsedEventHandler handler = new ElapsedEventHandler(Timer_Elapsed);
            mTimer.Elapsed += handler;
            mTimer.Enabled = true;
    
            //Manually execute the event handler on a threadpool thread.
            handler.BeginInvoke(this, null, new AsyncCallback(Timer_ElapsedCallback), handler);
        }
    
        private static void Timer_Elapsed(object source, ElapsedEventArgs e)
        {
            //Do stuff...
        }
    
        private void Timer_ElapsedCallback(IAsyncResult result)
        {
            ElapsedEventHandler handler = result.AsyncState as ElapsedEventHandler;
            if (handler != null)
            {
                handler.EndInvoke(result);
            }
        }
    }
    
        3
  •  7
  •   Nate Barbettini    8 年前

    我喜欢罗伯·库克的回答,所以我建了一个小房子 EagerTimer 子类的类 System.Timers.Timer 并添加了此功能(有来自 these articles )

    我知道我需要 System.Threading.Timer

    急切计时器

    /// <summary>
    // EagerTimer is a simple wrapper around System.Timers.Timer that
    // provides "set up and immediately execute" functionality by adding a
    // new AutoStart property, and also provides the ability to manually
    // raise the Elapsed event with RaiseElapsed.
    /// </summary>
    public class EagerTimer : Timer
    {
        public EagerTimer()
            : base() { }
    
        public EagerTimer(double interval)
            : base(interval) { }
    
        // Need to hide this so we can use Elapsed.Invoke below
        // (otherwise the compiler complains)
        private event ElapsedEventHandler _elapsedHandler;
        public new event ElapsedEventHandler Elapsed
        {
            add { _elapsedHandler += value; base.Elapsed += value; }
            remove { _elapsedHandler -= value; base.Elapsed -= value; }
        }
    
        public new void Start()
        {
            // If AutoStart is enabled, we need to invoke the timer event manually
            if (AutoStart)
            {
                this._elapsedHandler.BeginInvoke(this, null, new AsyncCallback(AutoStartCallback), _elapsedHandler); // fire immediately
            }
    
            // Proceed as normal
            base.Start();
        }
    
        private void AutoStartCallback(IAsyncResult result)
        {
            ElapsedEventHandler handler = result.AsyncState as ElapsedEventHandler;
            if (handler != null) handler.EndInvoke(result);
        }
    
        // Summary:
        //     Gets or sets a value indicating whether the EagerTimer should raise
        //     the System.Timers.Timer.Elapsed event immediately when Start() is called,
        //     or only after the first time it elapses. If AutoStart is false, EagerTimer behaves
        //     identically to System.Timers.Timer.
        //
        // Returns:
        //     true if the EagerTimer should raise the System.Timers.Timer.Elapsed
        //     event immediately when Start() is called; false if it should raise the System.Timers.Timer.Elapsed
        //     event only after the first time the interval elapses. The default is true.
        [Category("Behavior")]
        [DefaultValue(true)]
        [TimersDescription("TimerAutoStart")]
        public bool AutoStart { get; set; }
    
        /// <summary>
        /// Manually raises the Elapsed event of the System.Timers.Timer.
        /// </summary>
        public void RaiseElapsed()
        {
            if (_elapsedHandler != null)
                _elapsedHandler(this, null);
        }
    }
    

    [TestClass]
    public class Objects_EagerTimer_Tests
    {
        private const int TimerInterval = 10; // ms
    
        private List<DateTime> _timerFires = new List<DateTime>();
        private DateTime _testStart;
    
        [TestInitialize]
        public void TestSetup()
        {
            _timerFires.Clear();
            _testStart = DateTime.Now;
        }
    
        [TestMethod]
        public void Objects_EagerTimer_WithAutoStartDisabled()
        {
            // EagerTimer should behave as a normal System.Timers.Timer object
            var timer = new EagerTimer(TimerInterval);
            timer.AutoReset = false;
            timer.Elapsed += timerElapsed;
            timer.Start();
    
            // Wait (not enough time for first interval)
            Thread.Sleep(5);
            Assert.IsFalse(_timerFires.Any());
    
            // Wait a little longer
            Thread.Sleep(TimerInterval);
            Assert.AreEqual(1, _timerFires.Count);
        }
    
        [TestMethod]
        public void Objects_EagerTimer_WithAutoStartEnabled()
        {
            // EagerTimer should fire immediately on Start()
            var timer = new EagerTimer(TimerInterval);
            timer.AutoReset = false;
            timer.AutoStart = true;
            timer.Elapsed += timerElapsed;
            timer.Start();
    
            // Wait (not enough time for first interval)
            Thread.Sleep(5);
            Assert.IsTrue(_timerFires.Any());
    
            // Wait a little longer, now it will have fired twice
            Thread.Sleep(TimerInterval);
            Assert.AreEqual(2, _timerFires.Count);
        }
    
        [TestMethod]
        public void Objects_EagerTimer_WhenRaisingManually()
        {
            // EagerTimer should fire immediately on Start()
            var timer = new EagerTimer(TimerInterval);
            timer.AutoReset = false;
            timer.AutoStart = false;
            timer.Elapsed += timerElapsed;
    
            Assert.IsFalse(_timerFires.Any());
            timer.RaiseElapsed();
            Assert.IsTrue(_timerFires.Any());
        }
    
        private void timerElapsed(object sender, ElapsedEventArgs e) {
            _timerFires.Add(DateTime.Now);
        }
    }