Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在同一个类中处理多个计时器的最佳方法是什么?_C#_.net_Architecture - Fatal编程技术网

C# 在同一个类中处理多个计时器的最佳方法是什么?

C# 在同一个类中处理多个计时器的最佳方法是什么?,c#,.net,architecture,C#,.net,Architecture,我在课堂上使用了几个计时器,想知道实现它的两个选项: 选项1: 每条消息都有自己的计时器 class MessagesManager1 { Timer _timerA = new Timer(); Timer _timerB = new Timer(); Timer _timerC = new Timer(); public MessagesManager1() { _timerA.Interval = 1000; // 1 sec

我在课堂上使用了几个计时器,想知道实现它的两个选项:

选项1:

每条消息都有自己的计时器

 class MessagesManager1
{
    Timer _timerA = new Timer();
    Timer _timerB = new Timer();
    Timer _timerC = new Timer();

    public MessagesManager1()
    {
        _timerA.Interval = 1000; // 1 sec
        _timerB.Interval = 3000; // 3 sec
        _timerC.Interval = 5000; // 5 sec

        _timerA.Elapsed += _timerA_Elapsed;
        _timerB.Elapsed += _timerB_Elapsed;
        _timerC.Elapsed += _timerC_Elapsed;

        _timerA.Start();
        _timerB.Start();
        _timerC.Start();
    }

    void _timerA_Elapsed(object sender, ElapsedEventArgs e)
    {
        // send message A
    }

    void _timerB_Elapsed(object sender, ElapsedEventArgs e)
    {
        // send message B
    }

    void _timerC_Elapsed(object sender, ElapsedEventArgs e)
    {
        // send message C
    }
}
选项2: 仅使用一个计时器,根据SecondsCenter模数结果发送每条消息

 class MessagesManager2
{
    Timer _timer = new Timer();

    public MessagesManager2()
    {
        _timer.Interval = 1000; // 1 sec

        _timer.Elapsed += _timer_Elapsed;
        _timer.Start();
    }

    int secondsCounter;

    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // send message A

        if (secondsCounter % 3 == 0)
        {
            // send message B
        }

        if (secondsCounter % 5 == 0)
        {
            // send message C
        }
    }
}
哪一个更好,为什么?
(在性能、体系结构、维护、最佳实践等方面)。

我认为这些都不是

你应该遵循单一责任原则——在你的两种选择中,同一个类执行不止一件事情

我将创建一个只有一个计时器的类,然后在运行时创建该类的3个实例,并将间隔值传递给构造函数

根据在经过的事件中需要执行的操作,您可以将
操作
委托传递给构造函数,或者创建派生类,用所需的行为重写抽象/虚拟方法

方法1

如果您知道您只需要处理这三件事,那么我认为最好将它们定义为编译时的显式行为:

public abstract class BaseTimerHandler
{
    private readonly Timer m_Timer;

    public BaseTimerHandler(int interval)
    {
        m_Timer = new Timer();
        m_Timer.Interval = interval;
        m_Timer.Elapsed += TimerElapsed;
        m_Timer.Start();
    }

    protected abstract TimerElapsed(object sender, ElapsedEventArgs e);

    //TODO unsubscribe from Elapsed in Dispose method.
}

public class TimerAHandler : BaseTimerHandler
{
    private const int _INTERVAL = 1000;
    public TimerAHandler() : base(_INTERVAL) { }

    protected override TimerElapsed(object sender, ElapsedEventArgs e)
    {
        //send message A
    }
}

public class TimerBHandler : BaseTimerHandler
{
    private const int _INTERVAL = 3000;
    public TimerBHandler() : base(_INTERVAL) { }

    protected override TimerElapsed(object sender, ElapsedEventArgs e)
    {
        //send message B
    }
}

public class TimerCHandler : BaseTimerHandler
{
    private const int _INTERVAL = 5000;
    public TimerCHandler() : base(_INTERVAL) { }

    protected override TimerElapsed(object sender, ElapsedEventArgs e)
    {
        //send message C
    }
}
方法2

如果您谈论的是具有可变数量的这些计时器(可能在运行时定义),那么我将注入行为,而不是定义显式类(如果需要发送方或事件参数,请调整
操作
委托以包含参数)

这似乎有点过分,但我假设您的示例已简化。在这两种情况下,优点都是:

  • 您可以对计时器处理进行单元测试,将其与要在运行时间中执行的实际代码分开(在BaseTimerHandler中,您可以为单元测试创建一个模拟派生类型,在TimerHandler中,您可以插入一个伪
    操作
  • 您已经删除了计时器代码的重复,因此更易于维护并确保一致性
  • 如果要在经过的过程中执行的代码还包含一些公共代码,则可以将BaseTimerHandler.TimeRecursed扩展为虚拟方法并添加此公共代码,或者对于TimerHandler,可以将TimeRecursed扩展为包含公共代码

出于可维护性的原因,选择1,但实际上这取决于您,因为您将处理它。您能否提供更多详细信息(例如,您将拥有的预期计时器数量的上限)?一般来说,案例越容易阅读或理解越好,所以可能是你的第一个选择。没有足够的上下文来提供一个好的答案。你的第二个选择是过度杀戮;选项1可以正常工作。但这就是我们所能说的。您要求讨论“为什么?”这一问题无论如何都太宽泛了,但在任何情况下,这里都没有足够的细节来真正解决这一问题。可能没有足够的信息来提供性能方面的建设性答案,但在架构、维护和最佳实践方面还有很多需要继续讨论的内容。
public class TimerHandler
{
    private readonly Timer m_Timer;
    private readonly Action m_Elapsed;

    public BaseTimerHandler(int interval, Action sendMessage)
    {
        if (sendMessage == null)
            throw new ArgumentNullException("sendMessage", "Must provide send message");

        m_Timer = new Timer();
        m_Timer.Interval = interval;
        m_Timer.Elapsed += TimerElapsed;

        m_Elapsed = sendMessage;

        m_Timer.Start();
    }

    private TimerElapsed(object sender, ElapsedEventArgs e){
    {
        m_Elapsed();
    }

    //TODO unsubscribe from Elapsed in Dispose method.
}

var timerA = new TimerHandler(1, () => { //send message A });
var timerB = new TimerHandler(3, () => { //send message B });
var timerC = new TimerHandler(5, () => { //send message B });