2
\$\begingroup\$

I would like to execute a certain method at a given interval. The reason why I can't use a timer + its event handler right away is because I want to add an offset to each tick (100ms in my example below).

It seems to be working just as intented. The reason why I'm starting it manually is because if the _action(); takes more than the given tick time, I want to let it finish before starting a new "tick".

Perhaps this could be done in a much simpler way. I would like your thoughts on the code:

class RandomIntervalTask : IDisposable
{
    private readonly Timer _timer;
    private readonly int _initialInterval;
    private readonly int _range;
    private readonly Action _action;

    public RandomIntervalTask(int initialInterval, int range, Action action)
    {
        this._range = range;
        this._initialInterval = initialInterval;
        this._action = action;

        _timer = new Timer { AutoReset = false, Interval = initialInterval };
        _timer.Elapsed += TimerElapsed;
        _timer.Start();
    }

    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        var rnd = new Random();

        _timer.Interval = rnd.Next(_initialInterval, _initialInterval + _range);
        _action();
        _timer.Start();
    }

    public void Dispose()
    {
        _timer.Stop();
        _timer.Dispose();
    }
}

Executed like this:

var rit = new RandomIntervalTask(400, 100, DoStuff);

private void DoStuff()
{
    Debug.WriteLine("stuff");
}
\$\endgroup\$
  • \$\begingroup\$ My IDisposable (really my C#) is a little weaker than I like, but isn't that Dispose implementation open to a problem with a second call calling _timer.Stop() after _timer.Dispose()? \$\endgroup\$ – Michael Urman Dec 7 '13 at 2:01
  • \$\begingroup\$ @MichaelUrman I actually changed it to _timer.Dispose(); _timer = null; yesterday, and checked if the timer is not null before starting it in the event handler. Otherwise the last tick could run on a disposed timer. This should also take care of your issue. Thanks for the feedback. \$\endgroup\$ – Johan Dec 7 '13 at 18:49
4
\$\begingroup\$

Do not put the random number generator creation in the TimerElapsed method. This could wind up generating the same value if called in succession rapidly. Instead put it at the class level:

private readonly Random _rnd = new Random();

and change appropriately in the method.

\$\endgroup\$
  • 1
    \$\begingroup\$ I would add a Seed value to it too \$\endgroup\$ – Jeff Vanzella Dec 6 '13 at 23:51
  • \$\begingroup\$ @JeffVanzella You mean a constant seed? That would mean the sequence of “random” numbers would be always the same. Or do you mean something more complicated? \$\endgroup\$ – svick Dec 7 '13 at 0:43
  • \$\begingroup\$ Not a constant seed. There are a few examples in the link based off guids, datetime, and some others. \$\endgroup\$ – Jeff Vanzella Dec 8 '13 at 7:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.