如何使用Timer实现方法的定时循环调用(指定总时长)
实现带总时长限制的蜂鸣器状态循环处理器
原代码
internal class BuzzerStateTimedProcessor { private Timer _timer; private bool _executed = true; public BuzzerStateTimedProcessor() { _timer = new(OnTimer); } private void DurationOn() => Console.WriteLine("duration on"); private void DurationOff() => Console.WriteLine("duration off"); private TimeSpan _durationOff; private TimeSpan _durationOn; private TimeSpan _cycles; private TimeSpan _repeatCount; public void DurationCycle( TimeSpan? duration, TimeSpan durationOn, TimeSpan durationOff) { _durationOff = durationOff; _durationOn = durationOn; var permanentOperation = !duration.HasValue; if (permanentOperation) { _timer.Change(TimeSpan.Zero, durationOn); } else { _cycles = TimeSpan.Zero; _repeatCount = duration.Value; /// some logic } } private void OnTimer(object state) { if (_executed) DurationOn(); else DurationOff(); _executed = !_executed; } }
当前可用功能
调用DurationCycle时传入null作为总时长参数,可实现永久循环执行DurationOn()和DurationOff():
var test = new BuzzerStateTimedProcessor(); test.DurationCycle(null, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
执行效果:先执行DurationOn(),等待2秒后执行DurationOff(),再等待2秒,以此循环往复。
需求说明
需要补充逻辑,当传入总时长(比如10秒)时,在指定时长内循环执行上述方法,时间到后自动停止循环。调用示例如下:
var test = new BuzzerStateTimedProcessor(); test.DurationCycle(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
修改后的完整代码实现
通过添加时间记录、动态调整定时器间隔的方式实现时长限制:
internal class BuzzerStateTimedProcessor { private Timer _timer; private bool _executed = true; // 记录循环启动时间 private DateTime? _cycleStartTime; // 存储总时长限制 private TimeSpan? _totalDuration; public BuzzerStateTimedProcessor() { _timer = new(OnTimer); } private void DurationOn() => Console.WriteLine("duration on"); private void DurationOff() => Console.WriteLine("duration off"); private TimeSpan _durationOff; private TimeSpan _durationOn; public void DurationCycle( TimeSpan? duration, TimeSpan durationOn, TimeSpan durationOff) { _durationOff = durationOff; _durationOn = durationOn; _totalDuration = duration; var permanentOperation = !duration.HasValue; if (permanentOperation) { // 永久循环:首次立即执行,之后交替使用On/Off时长作为间隔 _timer.Change(TimeSpan.Zero, _durationOn); } else { // 带时长限制的循环:初始化启动时间,首次立即执行 _cycleStartTime = DateTime.Now; _timer.Change(TimeSpan.Zero, Timeout.InfiniteTimeSpan); } } private void OnTimer(object state) { // 执行当前状态对应的方法 if (_executed) DurationOn(); else DurationOff(); // 检查是否需要停止循环 if (_totalDuration.HasValue && _cycleStartTime.HasValue) { var elapsedTime = DateTime.Now - _cycleStartTime.Value; if (elapsedTime >= _totalDuration.Value) { _timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); return; } } // 切换状态,计算下一次触发的间隔 _executed = !_executed; var nextInterval = _executed ? _durationOn : _durationOff; // 避免下一次间隔超出剩余时长 if (_totalDuration.HasValue && _cycleStartTime.HasValue) { var elapsedTime = DateTime.Now - _cycleStartTime.Value; var remainingTime = _totalDuration.Value - elapsedTime; if (nextInterval > remainingTime) { _timer.Change(remainingTime, Timeout.InfiniteTimeSpan); return; } } // 设置下一次触发时间 _timer.Change(nextInterval, Timeout.InfiniteTimeSpan); } }
关键修改点
- 新增
_cycleStartTime和_totalDuration字段,分别记录循环启动时间和总时长限制 - 带时长限制的循环初始化时,将定时器设置为单次触发,后续在
OnTimer方法中动态调整下一次触发间隔 - 每次触发后计算已消耗时长,若超出总限制则停止定时器;若未超出,则检查下一次间隔是否会超过剩余时长,避免执行超出总时长的操作
- 统一永久循环和限时循环的间隔逻辑,确保两种模式下
On/Off的间隔都符合设置值
内容的提问来源于stack exchange,提问作者user14688948
相关产品推荐
相关产品推荐

