C# SetInterval SetTimeout的实现, 3种Timer的区别

212 阅读1分钟

问题

C#没有直接的定时器方法, 每次定时起来比较麻烦

解决办法

使用内置的定时器实现定时方法

实现代码

using System.Diagnostics;
namespace Main;

/// <summary>
/// 定时器 2023-10-26 Ciaran
/// </summary>
public static class TimerHelper
{
    /// <summary>
    /// 一次性定时器 2023-10-26 Ciaran
    /// </summary>
    /// <param name="fn"></param>
    /// <param name="interval"></param>
    /// <returns></returns>
    public static Timer SetTimeout(Action fn, long interval)
    {
        Timer? timer1 = null;
        var callback = new TimerCallback(_ =>
        {
            try
            {
                timer1!.Dispose();
            }
            catch (Exception)
            {
                // ignore
            }

            fn.Invoke();
        });
        timer1 = new Timer(callback, null, interval, -1);

        return timer1;
    }

    /// <summary>
    /// 循环定时器 2023-10-26 Ciaran
    /// </summary>
    /// <param name="fn"></param>
    /// <param name="interval"></param>
    /// <param name="times"></param>
    /// <returns></returns>
    public static Timer SetInterval(Action fn, long interval, ulong times = 0)
    {
        Timer? timer1 = null;
        ulong times2 = times;

        var callback = times > 0
            ? new TimerCallback(_ =>
            {
                if (--times == 0)
                {
                    try
                    {
                        timer1!.Dispose();
                    }
                    catch (Exception)
                    {
                        // ignore
                    }
                }
                else if (times2 <= times)
                {
                    try
                    {
                        timer1!.Dispose();
                    }
                    catch (Exception)
                    {
                        // ignore
                    }

                    return;
                }

                if (times < times2)
                {
                    times2 = times;
                }

                fn.Invoke();
            })
            : new TimerCallback(_ => { fn.Invoke(); });

        timer1 = new Timer(callback, null, interval, interval);

        return timer1;
    }
}


class ThreadInterrupt
{
    static void Main()
    {
        Stopwatch watch = Stopwatch.StartNew();
        int times = 0;
        TimerHelper.SetInterval(() =>
        {
            times++;
            Console.WriteLine($"times: {times}, elapsed: {watch.Elapsed}");
            System.Threading.Thread.Sleep(Timeout.Infinite);
            Console.WriteLine($"times: {times}, elapsed: {watch.Elapsed}");
        }, 3000, 5);

        Console.ReadKey();
        watch.Stop();
    }

}

参考文献

给c#添加SetTimeout和SetInterval函数(.NET Framework 3.5 System.Action命名空间) - supers - 博客园 (cnblogs.com)

System.Threading.Timer 和 System.Timers.Timer 的区别

System.Timers.Timer

System.Threading.Timer

通过源码得知, System.Timers.Timer 基于System.Threading.Timer实现.

System.Timers.Timer 基于事件和委托机制, 利于增加和减少执行方法; System.Threading.Timer 基于服务器多线程, 机制简单, 方便使用

关于 System.Windows.Forms.Timer

基于windows的Api实现, 引用 DLL: User32.dll

Timer 类 (System.Windows.Forms) | Microsoft Learn

计时器 - Win32 apps | Microsoft Learn

SetTimer 函数 (winuser.h) - Win32 apps | Microsoft Learn