如何在 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)
{
}
}
场景流程
考虑 'MessageReceiveAsync' 我收到一个主题,其中包含一个名为 'start' 的方法(不是 C# 方法),这是第一次使用一些元数据,然后是 'PublishToMethod'使用该方法名称调用 ('start')
然后根据 'start' 案例中接收到的元数据,我根据接收到的元数据以及 'start' 命令将计时器启动到特定时间间隔。
然后下面三个数据都会按设定的时间间隔发送
await SendPeriodicTimeSeries(PublisherClass.TimeSeriesTopic,
PublisherClass.TelemetrySingle, PublisherClass.Configuration);
await SendPeriodicAlarm(PublisherClass.AlarmTopic, PublisherClass.AlarmSingle);
await SendPeriodicEvent(PublisherClass.EventTopic, PublisherClass.EventSingle);
考虑 'MessageReceiveAsync' 我收到了另一个主题,其中包含一个名为 'start' 的方法(不是 C# 方法),这是第二次使用不同的元数据。可以打任意次数。
然后应该再次为计时器设置特定的时间间隔,并且计时器事件必须针对不同类型的元数据定期进行
之前的周期数据应该也照常进行
此外,每当调用 '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)
{
}
}
问题陈述
我有一个用 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)
{
}
}
场景流程
考虑 'MessageReceiveAsync' 我收到一个主题,其中包含一个名为 'start' 的方法(不是 C# 方法),这是第一次使用一些元数据,然后是 'PublishToMethod'使用该方法名称调用 ('start')
然后根据 'start' 案例中接收到的元数据,我根据接收到的元数据以及 'start' 命令将计时器启动到特定时间间隔。
然后下面三个数据都会按设定的时间间隔发送
await SendPeriodicTimeSeries(PublisherClass.TimeSeriesTopic, PublisherClass.TelemetrySingle, PublisherClass.Configuration); await SendPeriodicAlarm(PublisherClass.AlarmTopic, PublisherClass.AlarmSingle); await SendPeriodicEvent(PublisherClass.EventTopic, PublisherClass.EventSingle);
考虑 'MessageReceiveAsync' 我收到了另一个主题,其中包含一个名为 'start' 的方法(不是 C# 方法),这是第二次使用不同的元数据。可以打任意次数。
然后应该再次为计时器设置特定的时间间隔,并且计时器事件必须针对不同类型的元数据定期进行
之前的周期数据应该也照常进行
此外,每当调用 '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)
{
}
}