C# 定时器封装版

一、概述

在 Winform 等平台开发中,经常会用到定时器的功能,但项目定时器一旦写多了,容易使软件变卡,而且运行时间长了会造成软件的闪退,这个可能是内存溢出造成的,具体原因我也没去深究,另一个,就是在关闭软件时,经常关不掉,因为这时候定时器的线程依然还在运行,你就要把这些定时器一个个关闭,才能关闭软件,或者直接使用强制退出程序代码,非常的麻烦,后面我在想能不能封装一个定时器,使用事件的订阅机制来实现功能,后面就实现了这些功能,那么下面就开始搬代码吧。

二、实现功能

新建一个 winform 项目,添加一个类 ScanTimer.cs  。

代码:

using System;
using System.Threading;

/// <summary>
/// 定时器
/// </summary>
public class ScanTimer
{
    /// <summary>
    /// 定时器回调事件
    /// </summary>
    public static event Action ScanEvent;
    /// <summary>
    /// 定时器开关的状态
    /// </summary>
    public static Action<bool> TimerStatus = null;
    /// <summary>
    /// 定时器执行的次数
    /// </summary>
    public static Action<int> TimerExecuteCount = null;

    /// <summary>
    /// 定时器是否打开
    /// </summary>
    public static bool IsOpen
    {
        get
        {
            if (Timer == null)
                return false;
            return Timer.Enabled;
        }
    }

    //定时器
    private static System.Timers.Timer Timer = null;
    //间隔时间
    private const int IntervalTime = 2000;
    //定时清理控制台日志
    private static int OutCount = 0;
    //是否初始化
    private static bool IsInit = false;


    /// <summary>
    /// 初始化
    /// </summary>
    private static void Init()
    {
        //实例化Timer类,
        Timer = new System.Timers.Timer();
        //设置间隔时间(毫秒);
        Timer.Interval = IntervalTime;
        //到达时间的时候执行事件;
        Timer.Elapsed += new System.Timers.ElapsedEventHandler(Elapsed);
        //设置是执行一次(false)还是一直执行(true);
        Timer.AutoReset = true;

        IsInit = true;
    }

    /// <summary>
    /// 定时器
    /// </summary>
    /// <param name="source"></param>
    /// <param name="e"></param>
    private static void Elapsed(object source, System.Timers.ElapsedEventArgs e)
    {
        OutCount++;
        if (OutCount > 10000)
        {
            OutCount = 0;
            //Console.Clear();
        }

        //定时器的执行次数
        if (TimerExecuteCount != null)
            TimerExecuteCount(OutCount);

        //执行回调
        if (ScanEvent != null)
            ScanEvent();
    }

    /// <summary>
    /// 打开定时器
    /// </summary>
    public static void Start()
    {
        if (!IsInit) Init();

        Timer.Enabled = true;
        OutCount = 0;

        if (TimerStatus != null)
            TimerStatus(true);
    }

    /// <summary>
    /// 关闭定时器
    /// </summary>
    public static void Stop()
    {
        Timer.Enabled = false;
        OutCount = 0;

        if (TimerStatus != null)
            TimerStatus(false);
    }

    /// <summary>
    /// 清除所有的事件
    /// </summary>
    public static void ClearAllEvent()
    {
        if (ScanEvent == null) return;
        Delegate[] dels = ScanEvent.GetInvocationList();
        foreach (Delegate del in dels)
        {
            ScanEvent -= del as Action;
        }
        Console.WriteLine("[ClearAllEvent]清除定时器所有的事件");
    }

    /// <summary>
    /// 获取定时器任务的个数
    /// </summary>
    /// <returns></returns>
    public static int GetTaskCount()
    {
        if (ScanEvent == null) return 0;
        Delegate[] dels = ScanEvent.GetInvocationList();
        return dels.Length;
    }

    /// <summary>
    /// 是否存在某个任务
    /// </summary>
    /// <param name="taskName"></param>
    /// <returns></returns>
    public static bool IsExistTask(string taskName)
    {
        if (ScanEvent == null)
            return false;

        Delegate[] dels = ScanEvent.GetInvocationList();
        foreach (Delegate del in dels)
        {
            object delObj = del.GetType().GetProperty("Method").GetValue(del, null);
            string funcName = (string)delObj.GetType().GetProperty("Name").GetValue(delObj, null);
            if (funcName == taskName) return true;
        }

        return false;
    }


    private ScanTimer() { }
}

给 Form1 窗体添加 Form1_Load,Form1_FormClosing 事件。

Form1_Load 事件是窗体启动时执行一次,在这里可以启动定时器。

Form1_FormClosing 事件是在窗体关闭时执行一次,在这里我们可以关闭定时器。

如下图:

扫描二维码关注公众号,回复: 16152968 查看本文章

三、测试

ScanTimer 的 ScanEvent 字段是一个事件,这里就是我们需要添加订阅机制的地方。

public static event Action ScanEvent;

其实原理也很简单,就是在 ScanTimer 类中封装一个定时器,每隔多少秒去执行一次这个事件,然后所有订阅这个事件的方法,都会被执行到。

在调用 ScanTimer 类之前,先把 winform 的输出类型改为 控制台应用程序,这样更方便的观察。

代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 定时器
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ScanTimer.ScanEvent += Timer;

            ScanTimer.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ScanTimer.Stop();
        }

        private void Timer()
        {
            Console.WriteLine("定时器");
        }
    }
}

调用也非常的简单,只需要写一个 Timer() 方法,然后添加到 ScanEvent 这个事件中就好了,我们运行看看效果

另外,在 ScanTimer 类中我还封装了其他的方法,比如,你不知道定时器是否还在执行中,有时候执行代码,不一定需要在代码中打印, 可以使用 TimerExecuteCount 这个委托查看定时器执行了多少次,也可以通过 TimerStatus 这个委托,来查看定时器是否在执行。

代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 定时器
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ScanTimer.ScanEvent += Timer;
            ScanTimer.TimerStatus += TimerStatus;
            ScanTimer.TimerExecuteCount += TimerExecuteCount;

            ScanTimer.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ScanTimer.Stop();
        }

        private void Timer()
        {
            Console.WriteLine("定时器");
        }

        private void TimerStatus(bool sw)
        {
            Console.WriteLine("定时器的状态:{0}", sw);
        }

        private void TimerExecuteCount(int count)
        {
            Console.WriteLine("定时器执行次数:{0}", count);
        }
    }
}

运行:

在这里,TimerExecuteCount 和 TimerStatus 这两个委托是 Action 类型,如果其他的类不需要订阅这两个委托,不用使用 += ,可以直接使用 = 号就行。

ScanTimer.ScanEvent += Timer;
ScanTimer.TimerStatus = TimerStatus;
ScanTimer.TimerExecuteCount = TimerExecuteCount;

结束

如果这个帖子对你有所帮助,欢迎 关注 、点赞 、留言

end

猜你喜欢

转载自blog.csdn.net/qq_38693757/article/details/131979981