如何在 C# 中使用定时器事件调用多个实例

How to invoke multiple instances using timer events in C#

问题陈述

我有一个用 C# 编写的模块代码,它等待一个名为 'start' 的主题,一旦收到它,我就需要根据 om 时间间隔定期发送某些数据。我需要以这样一种方式来适应我的逻辑,即可以使用不同的元数据值多次调用 'start' 主题,并且所有这些都必须 运行 它是具有相同逻辑的自己的实例。

我面临的问题

现在,即使 'start' 主题被多次调用,代码始终 运行 仅 'SendPeriodicTelemetry' 的一个实例。

代码片段示例

下面三个 类 是按调用顺序给出的

public static async void MessageReceiveAsync(object sender, MqttApplicationMessageReceivedEventArgs e)
        {            
            Console.WriteLine($"Message received on topic: '{e.ApplicationMessage.Topic}'. Payload: {msg}");           
            try
            {
                if (e.ApplicationMessage.Topic.Contains("methods"))
                {                   
                    await PublisherClass.PublishToMethod(topicElement, msg);
                }
            }
        }


public static class PublisherClass
    {
         public static bool StartInvoked { get; set; }
         public static int StartCmdCount { get; set; } = 0;
          public static async Task PublishToMethod(string methodName, string message)
        {
            try
            {
                string topic;                
                var sendPeriodicTelemetries = new SendPeriodicTelemetry[10];
                switch (methodName)
                {         
                    case "stop":                        
                        for (int i = 0; i < StartCmdCount; i++)
                        {
                            Console.WriteLine($"start command index to stop: {i}");
                            sendPeriodicTelemetries[StartCmdCount].aTimer.Stop();
                            sendPeriodicTelemetries[StartCmdCount].aTimer.Dispose();
                        }
                        StartInvoked = false;
                        StartCmdCount = 0;
                        await CommonMethods.AckMethod(CommonMethods.listMessage, CommonMethods.requestId, MethodNames.sendTimeSeries);
                        break;

                    case "start":                      
                        sendPeriodicTelemetries[StartCmdCount] = new SendPeriodicTelemetry();                        
                        sendPeriodicTelemetries[StartCmdCount].TsAlarmAndEventTopicAndPayload(rawPayload, objId);                       
                        sendPeriodicTelemetries[StartCmdCount].aTimer = new System.Timers.Timer(timeIntervel);             
                        sendPeriodicTelemetries[StartCmdCount].SetTimer(timeIntervel, sendPeriodicTelemetries[StartCmdCount].aTimer);
                        StartCmdCount++;              
                        break;                   
                }
            }

            catch(Exception exception)
            {
                Console.WriteLine($"Exception occurred: {exception.ToString()}");
            }
        }        
    }
    
    public class SendPeriodicTelemetry
    {
       
        public void TsAlarmAndEventTopicAndPayload(JObject rawPayload, string objId)
        {
            
        }

        public void SetTimer(int timeInterval, Timer timer)
        {
            if (!PublisherClass.StartInvoked)
            {               
                PublisherClass.StartInvoked = true;
                timer.Elapsed += SendPeriodic;
                timer.AutoReset = true;
                timer.Enabled = true;
            }
        }

        public async void SendPeriodic(Object source, ElapsedEventArgs e)
        {           
            Console.WriteLine("Starting to send periodic Telemetry at {0:HH:mm:ss.fff}", e.SignalTime);
            await SendPeriodicTimeSeries(PublisherClass.TimeSeriesTopic, PublisherClass.TelemetrySingle, PublisherClass.Configuration);
            await SendPeriodicAlarm(PublisherClass.AlarmTopic, PublisherClass.AlarmSingle);
            await SendPeriodicEvent(PublisherClass.EventTopic, PublisherClass.EventSingle);
        }

        public async Task SendPeriodicTimeSeries(string topic, TelemetrySingle payload, JObject configuration)
        {
           
        }

        public async Task SendPeriodicAlarm(string topic, AlarmSingle payload)
        {
           
        }

        public async Task SendPeriodicEvent(string topic, EventSingle payload)
        {
           
        }
    }

场景流程

  1. 考虑 'MessageReceiveAsync' 我收到一个主题,其中包含一个名为 'start' 的方法(不是 C# 方法),这是第一次使用一些元数据,然后是 'PublishToMethod'使用该方法名称调用 ('start')

  2. 然后根据 'start' 案例中接收到的元数据,我根据接收到的元数据以及 'start' 命令将计时器启动到特定时间间隔。

  3. 然后下面三个数据都会按设定的时间间隔发送

             await SendPeriodicTimeSeries(PublisherClass.TimeSeriesTopic, 
                             PublisherClass.TelemetrySingle, PublisherClass.Configuration);
             await SendPeriodicAlarm(PublisherClass.AlarmTopic, PublisherClass.AlarmSingle);
             await SendPeriodicEvent(PublisherClass.EventTopic, PublisherClass.EventSingle);
    
  4. 考虑 'MessageReceiveAsync' 我收到了另一个主题,其中包含一个名为 'start' 的方法(不是 C# 方法),这是第二次使用不同的元数据。可以打任意次数。

  5. 然后应该再次为计时器设置特定的时间间隔,并且计时器事件必须针对不同类型的元数据定期进行

  6. 之前的周期数据应该也照常进行

  7. 此外,每当调用 'stop' 方法时,所有实例的周期性计时器事件都应停止。

实际结果

当我第二次收到 'start' 时,第一次调用的元数据值全部切换到第二次调用的值,并且周期性数据始终为最新调用的值。只有一个实例总是 运行ning。我想发送与调用 'start' 次数一样多的实例的周期性数据。

预期结果

应该调用定时器事件的多个实例,并且下面的方法应该根据接收到的元数据继续发送数据

        await SendPeriodicTimeSeries(PublisherClass.TimeSeriesTopic, 
        PublisherClass.TelemetrySingle, PublisherClass.Configuration);
        await SendPeriodicAlarm(PublisherClass.AlarmTopic, PublisherClass.AlarmSingle);
        await SendPeriodicEvent(PublisherClass.EventTopic, PublisherClass.EventSingle);

Timer 对象初始化时出现问题。它仍然来自静态 class,因此使用 'SendPeriodicTelemetry' 实例级别 属性 更改了它。然后现在我可以在指定的时间间隔内调用多个实例。为了停止那些基于时间的事件,我需要处理定时器。而已。实现了我的 objective。而且不需要初始化 'SendPeriodicTelemetry' 对象作为数组来实现。

public static async void MessageReceiveAsync(object sender, MqttApplicationMessageReceivedEventArgs e)
    {            
        Console.WriteLine($"Message received on topic: '{e.ApplicationMessage.Topic}'. Payload: {msg}");           
        try
        {
            if (e.ApplicationMessage.Topic.Contains("methods"))
            {                   
                await PublisherClass.PublishToMethod(topicElement, msg);
            }
        }
    }


public static class PublisherClass
{   
     public static List<System.Timers.Timer> SendPeriodicTimerObjs { get; set; } = new List<System.Timers.Timer>();
     public static async Task PublishToMethod(string methodName, string message)
    {
        try
        {                
            switch (methodName)
            {       
                case "start":
                case "stop":                        
                    var sendPeriodicObj = new SendPeriodicTelemetry();
                    sendPeriodicObj.periodicTimer = new System.Timers.Timer();
                    SendPeriodicTimerObjs.Add(sendPeriodicObj.periodicTimer);
                    if (methodName == "start")
                    {                                             
                        sendPeriodicObj.TsAlarmAndEventTopicAndPayload(rawPayload, objId);                           
                        sendPeriodicObj.periodicTimer.Interval = timeIntervel;                           
                        sendPeriodicObj.SetTimer(timeIntervel, sendPeriodicObj.periodicTimer);                
                    }
                    else
                    {                
                        sendPeriodicObj.periodicTimer.Stop();                            
                        foreach(var timer in SendPeriodicTimerObjs)
                        {
                            timer.Dispose();
                        }                           
                        SendPeriodicTimerObjs.Clear();                 
                    }
                    break;                
            }
        }

        catch(Exception exception)
        {
            Console.WriteLine($"Exception occurred: {exception.ToString()}");
        }
    }        
}

public class SendPeriodicTelemetry
{
    public System.Timers.Timer periodicTimer;
    
    public void TsAlarmAndEventTopicAndPayload(JObject rawPayload, string objId)
    {
        
    }

    public void SetTimer(int timeInterval, Timer timer)
    {
        Console.WriteLine($"Inside SetTimer method");
        StartInvoked = true;
        timer.Elapsed += SendPeriodic;
        timer.AutoReset = true;
        timer.Enabled = true;           
    }  

    public async void SendPeriodic(Object source, ElapsedEventArgs e)
    {           
        Console.WriteLine("Starting to send periodic Telemetry at {0:HH:mm:ss.fff}", e.SignalTime);
        await SendPeriodicTimeSeries(PublisherClass.TimeSeriesTopic, PublisherClass.TelemetrySingle, PublisherClass.Configuration);
        await SendPeriodicAlarm(PublisherClass.AlarmTopic, PublisherClass.AlarmSingle);
        await SendPeriodicEvent(PublisherClass.EventTopic, PublisherClass.EventSingle);
    }

    public async Task SendPeriodicTimeSeries(string topic, TelemetrySingle payload, JObject configuration)
    {
       
    }

    public async Task SendPeriodicAlarm(string topic, AlarmSingle payload)
    {
       
    }

    public async Task SendPeriodicEvent(string topic, EventSingle payload)
    {
       
    }
}