C# 三种定时器的用法

熊思宇 2024-10-03 14:35:03 阅读 83

目录

1.System.Timers.Timer

2.System.Windows.Forms.Timer

3.System.Threading.Timer

4.简单的封装


这里介绍三种常用的定时器,方便查阅资料或直接复制使用。

1.System.Timers.Timer

<code>System.Timers.Timer 类定义了一个计时器,该计时器按固定间隔触发事件。它主要用于多线程环境,特别是在基于服务器的组件或服务组件中。此类没有用户界面,在运行时不可见,特别适用于后台任务处理。

主要属性和方法

Interval:以毫秒为单位,设置或获取引发 Elapsed 事件的时间间隔。AutoReset:设置或获取一个值,该值指示计时器在 Elapsed 事件触发后是否自动重置,并继续计时(true)或停止计时(false)。Enabled:设置或获取一个值,该值指示计时器是否已启用(true)或已禁用(false)。Start():通过将 Enabled 设置为 true 来启动计时器。Stop():通过将 Enabled 设置为 false 来停止计时器。Elapsed 事件:当指定的时间间隔过去时,将触发此事件。该事件处理函数在新的线程中执行,因此不能直接访问UI控件(需通过委托和Invoke方法)。

使用场景

适用于需要按固定时间间隔执行任务的后台服务或应用程序,如定期检查数据库、更新状态信息等。

用法:

namespace Test2

{

internal class Program

{

private static System.Timers.Timer Timer;

static void Main(string[] args)

{

Timer = new System.Timers.Timer();

Timer.Interval = 2000; //间隔时间2000毫秒

Timer.AutoReset = true;//是否重复执行

Timer.Elapsed += Timer_Elapsed;

Timer.Enabled = true; //或者使用 Timer.Start() 效果一样

Console.ReadKey();

}

private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)

{

Console.WriteLine("需要重复执行的代码");

}

}

}

2.System.Windows.Forms.Timer

System.Windows.Forms.Timer 控件是Windows窗体环境中的定期事件引发组件。它主要用于单线程环境,特别是在UI更新中。该计时器是同步的,意味着它在UI线程上执行,不会阻塞或干扰UI操作。

主要属性和方法

Interval:以毫秒为单位,设置或获取计时器事件之间的时间间隔。Enabled:设置或获取一个值,该值指示计时器是否已启用(true)或已禁用(false)。Start():启动计时器。Stop():停止计时器。Tick 事件:当指定的时间间隔过去时,将触发此事件。与 System.Timers.Timer 不同,Tick 事件在UI线程上执行,因此可以直接访问UI控件。

使用场景

适用于需要按固定时间间隔更新UI元素的场景,如时钟、动画、进度条更新等。

System.Windows.Forms.Timer 可以在 Winform 工具箱中直接拖入到 Winform 界面中,也可以直接在代码中添加,System.Windows.Forms.Timer 在定时器回调中可以调用 Winform 的界面控件,而 System.Timers.Timer 回调内使用 Winform 控件会存在跨线程的错误。

用法同 System.Timers.Timer 差不多,用工具箱中的 Timer 可以少写很多代码。

代码:

<code>using System;

using System.Windows.Forms;

namespace Test1

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

System.Windows.Forms.Timer Timer;

private void Form1_Load(object sender, EventArgs e)

{

Timer = new System.Windows.Forms.Timer();

Timer.Interval = 1000;

Timer.Tick += Timer_Tick;

Timer.Start();

}

private void Timer_Tick(object sender, EventArgs e)

{

Console.WriteLine("需要重复执行的代码");

}

}

}

3.System.Threading.Timer

System.Threading.Timer 类由线程池调用,专门用于在线程池线程上按固定间隔执行单个回调方法。它是为服务器或后台应用程序设计的,可以优化系统资源的使用。

主要属性和方法

Callback:定义在指定时间间隔后调用的回调方法。State:传递给回调方法的对象,作为回调方法的参数。DueTime:计时器第一次触发之前延迟的时间(以毫秒为单位)。Period:计时器每次触发之间的时间间隔(以毫秒为单位)。设置为 Timeout.Infinite 表示计时器只触发一次。Change(Int64, Int64):在计时器启动后更改其 DueTime 和 Period 设置。Dispose():释放 Timer 对象使用的资源。

使用场景

适用于需要定期执行长时间运行或资源密集型任务的后台应用程序,如文件清理、数据同步等。由于回调方法在线程池线程上执行,因此不会影响UI线程的性能。

代码:

namespace Test2

{

internal class Program

{

private static System.Threading.Timer Timer;

static void Main(string[] args)

{

//参数1 要定时执行的回调

//参数2 定时回调的参数

//参数3 延迟多少秒开始执行

//参数4 定时器的间隔时间

Timer = new System.Threading.Timer(OnTimedEvent, null, 0, 1000);

Console.ReadKey();

}

private static void OnTimedEvent(Object state)

{

Console.WriteLine("需要重复执行的代码");

}

}

}

可以使用下面的方法来停止定时器

// 暂时停止定时器

Timer.Change(Timeout.Infinite, Timeout.Infinite);

如果需要继续执行定时器,可以使用下面的方法

// 重新启动定时器:初始延迟1000毫秒,每2000毫秒触发一次

Timer.Change(1000, 2000);

其实还有一个定时器 System.Web.UI.Timer,只是现在用的人比较少,这里就不做介绍了。

4.简单的封装

根据上面的代码可以发现,就那几行代码,复制来复制去的有点麻烦,我这里稍微封装一下,一句代码搞定定时器,非常的方便。

新建一个类 TimerScheduler

using System;

using System.Collections.Generic;

using System.Threading.Tasks;

/// <summary>

/// 定时器的封装

/// </summary>

public class TimerScheduler

{

private static Dictionary<string, ActionSchedulerInfo> SchedulerDic = new Dictionary<string, ActionSchedulerInfo>();

/// <summary>

/// 添加定时执行委托

/// </summary>

/// <param name="key">唯一的Key</param>code>

/// <param name="intervalInSeconds">定时器间隔时间</param>code>

/// <param name="isUIThread">是否是UI线程</param>code>

/// <param name="action">定时器回调</param>code>

public static void Add(string key, double intervalInSeconds, bool isUIThread, Action action)

{

if (action == null)

{

Console.WriteLine("参数 action 不能为空");

return;

}

if (string.IsNullOrEmpty(key))

{

Console.WriteLine("参数 key 不能为空");

return;

}

if (SchedulerDic.ContainsKey(key))

{

Console.WriteLine($"{key} 不能重复的添加");

return;

}

if (intervalInSeconds <= 0 || intervalInSeconds > 86400)

{

Console.WriteLine($"{key} 的间隔时间超过了指定的范围");

return;

}

var actionScheduler = new ActionSchedulerInfo();

if (isUIThread)

{

actionScheduler.timerUI = new System.Windows.Forms.Timer();

actionScheduler.timerUI.Interval = (int)TimeSpan.FromSeconds(intervalInSeconds).TotalMilliseconds;

actionScheduler.timerUI.Tick += (sender, e) => action();

actionScheduler.timerUI.Start();

}

else

{

actionScheduler.timer = new System.Timers.Timer();

actionScheduler.timer.Interval = TimeSpan.FromSeconds(intervalInSeconds).TotalMilliseconds;

actionScheduler.timer.Elapsed += (sender, e) => Task.Run(action);

actionScheduler.timer.AutoReset = true;

actionScheduler.timer.Start();

}

SchedulerDic[key] = actionScheduler;

}

/// <summary>

/// 移除定时执行委托

/// </summary>

/// <param name="key"></param>code>

public static void Remove(string key)

{

if (SchedulerDic.TryGetValue(key, out var scheduler))

{

if (scheduler.timer != null)

{

scheduler.timer.Stop();

scheduler.timer.Dispose();

}

if (scheduler.timerUI != null)

{

scheduler.timerUI.Stop();

scheduler.timerUI.Dispose();

}

scheduler.actions = null;

SchedulerDic.Remove(key);

}

}

/// <summary>

/// 移除所有的定时器

/// </summary>

public static void Dispose()

{

foreach (var scheduler in SchedulerDic.Values)

{

if (scheduler.timer != null)

{

scheduler.timer.Stop();

scheduler.timer.Dispose();

scheduler.actions = null;

}

if (scheduler.timerUI != null)

{

scheduler.timerUI.Stop();

scheduler.timerUI.Dispose();

scheduler.actions = null;

}

}

SchedulerDic.Clear();

}

public class ActionSchedulerInfo

{

public System.Timers.Timer timer { get; set; }

public System.Windows.Forms.Timer timerUI { get; set; }

public Action actions { get; set; }

}

}

添加:

TimerScheduler.Add("Test", 2, false, () =>

{

Console.WriteLine("这是一个定时器");

});

这里使用了一个 Lambda 表达式,你可以直接替换成一个无参数的方法。

移除:

TimerScheduler.Remove("Test");

移除对应的 key,就能停止和清除这个定时器了。

end



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。