Interesting all the different answers. Here is a simple DIY parameter that does not depend on any other libraries and does not require excessive use of stream resources.
Basically, for each action in your list, an onTick function is created that performs this action and then calls DoThings recursively with the rest of the actions and delays.
Here ITimer
is just a simple wrapper around DispatcherTimer
(but it will work with a SWF timer, or a mock timer for unit testing), and DelayedAction
is just a Tuple with int Delay
and Action action
public static class TimerEx { public static void DoThings(this ITimer timer, IEnumerable<DelayedAction> actions) { timer.DoThings(actions.GetEnumerator()); } static void DoThings(this ITimer timer, IEnumerator<DelayedAction> actions) { if (!actions.MoveNext()) return; var first = actions.Current; Action onTick = null; onTick = () => { timer.IsEnabled = false; first.Action();
If you do not want to delve into F # or the Rx link or use .Net 4.5, this is a simple viable solution.
Here is an example of how to test it:
[TestClass] public sealed class TimerExTest { [TestMethod] public void Delayed_actions_should_be_scheduled_correctly() { var timer = new MockTimer(); var i = 0; var action = new DelayedAction(0, () => ++i); timer.DoThings(new[] {action, action}); Assert.AreEqual(0, i); timer.OnTick(); Assert.AreEqual(1, i); timer.OnTick(); Assert.AreEqual(2, i); timer.OnTick(); Assert.AreEqual(2, i); } }
And here are other classes to compile it:
public interface ITimer { bool IsEnabled { set; } double Interval { set; } event Action Tick; } public sealed class Timer : ITimer { readonly DispatcherTimer _timer; public Timer() { _timer = new DispatcherTimer(); _timer.Tick += (sender, e) => OnTick(); } public double Interval { set { _timer.Interval = TimeSpan.FromMilliseconds(value); } } public event Action Tick; public bool IsEnabled { set { _timer.IsEnabled = value; } } void OnTick() { var handler = Tick; if (handler != null) { handler(); } } } public sealed class MockTimer : ITimer { public event Action Tick; public bool IsEnabled { private get; set; } public double Interval { set { } } public void OnTick() { if (IsEnabled) { var handler = Tick; if (handler != null) { handler(); } } } } public sealed class DelayedAction { readonly Action _action; readonly int _delay; public DelayedAction(int delay, Action action) { _delay = delay; _action = action; } public Action Action { get { return _action; } } public int Delay { get { return _delay; } } }