通过依赖项注入传递计时器,并配置/启动计时器

本文关键字:计时器 启动 配置 依赖 注入 | 更新日期: 2023-09-27 18:23:44

我在这里遇到了一种情况,在我的类中需要一个计时器,它根据时间间隔调用一些方法。

在正常情况下,我会实例化计时器,并在构造函数中配置它。但我想以依赖注入的方式来做。在构造函数中传递计时器很容易,但为了将方法绑定到其OnTimeElapsed很棘手,工厂是否应该实例化该类,配置该计时器?我应该如何在不违反dpendency注入原则的情况下继续。

感谢

第1版

好吧,让我重新表述一下我真正想问的问题。
  1. 根据发布的视频米斯科
  2. 在他的其他谈话中(永远不要测试你的框架:.net框架此处)
  3. 在他的代码审查中引导任何东西在构造函数中超出字段赋值的操作被认为是糟糕的

我实现依赖注入的主要目标是,我需要在特定的时间内对其进行单元测试,无论是否调用了方法。

所以我的问题是:我应该在哪里绑定OnTimerElpsed事件?我真的想在这里测试计时器吗?我好像在这里迷路了

好心帮忙。

通过依赖项注入传递计时器,并配置/启动计时器

如果你的问题是,你想依赖注入一个定时器,稍后可以将事件绑定到它,那么应该很简单。

只需创建Timer类以遵循ITimer接口,并在其上创建方法以执行所需的操作。

public class Calendar
{
    public Calendar(ITimer timer)
    {
        // timer is the dependency injected timer
        timer.SetEvent(EventReminder, 3600);
    }
    public void EventReminder()
    {
        Console.Write("Hey, it's time for your appointment!");
    }
}
public interface ITimer
{
    void SetEvent(Action callbackMethod, int interval);
}

在这种情况下,您有一个日历应用程序,并且希望您的应用程序具有计时器。但你不在乎计时器是如何工作的,甚至不在乎什么样的计时器(也许你想要一个以分钟、小时或其他方式工作的计时器)。你只知道你想要一个定时器,所以你依赖注入一个。

您必须创建一个接口,定义计时器将执行的操作,因为尽管它不关心您使用的计时器,但它确实关心计时器的功能。在我们的例子中,计时器可以做一件事——将事件设置为在某个时间间隔后发生。

因此,我们注入了计时器,但为了能够使用或设置它,我们使用接口来定义方法。我们永远不知道它在内部是如何工作的——我们甚至不知道它有一个OnElapsedEvent,我们也不在乎。留给计时器的创建者,我们只需要一个方法来完成任务,这就是上面的代码所展示的。

为依赖注入的新手发布答案。

我以前的问题代码在这里:

public class MyClassInvoker:IDisposable
{
    readonly Timer _myTimer;
    readonly MyClass _myclass;
    public MyClassInvoker(Timer myTimer, MyClass myclass)
    {
        _myTimer = myTimer;
        _myclass = myclass;
        _myTimer.Interval = 3000;//configure Your timer here
        _myTimer.Elapsed +=new ElapsedEventHandler(PeriodicInvoker); 
    }
    public void Start()
    {
        _myTimer.Start();
    }
    public void Dispose()
    {
        _myTimer.Dispose();
    }
    void PeriodicInvoker(object sender, EventArgs e)
    {
        _myclass.DoSomePeriodicWork();
    }
}

修改代码后,它看起来像:

public class MyClassInvoker:IDisposable
{
    readonly Timer _myTimer;
    readonly MyClass _myclass;
    public MyClassInvoker(MyClass myclass)
    {
        _myTimer = new Timer();
        _myclass = myclass;
    }
    public void Start()
    {
        _myTimer.Interval = 3000;//configure Your timer here
        //add or remove any previous listeners 
        //here depending upon the business needs
        _myTimer.Elapsed += new ElapsedEventHandler(PeriodicInvoker); 
        _myTimer.Start();
    }
    public void Dispose()
    {
        _myTimer.Dispose();
    }
    void PeriodicInvoker(object sender, EventArgs e)
    {
        _myclass.DoSomePeriodicWork();
    }
}

在直观地思考了这个问题之后,我发布了分析:

  1. 根据我自己的问题中发布的链接,永远不要在构造函数。我实际上是在绑一个构造函数中的事件处理程序我现在还不能评论什么如果我这样做可能会产生影响
  2. 我在以前的代码中传递了一个Timer对象,以便可测试性

带说明的解决方案

  1. 通过将Timer作为依赖项传递,我试图给接口来模拟.Net Timer BCL,以便单元测试以及进行替换。目前.Net 中有三种定时器

    • System.Threading.Timer
    • System.Timers.Timer
    • System.Windows.Forms.Timer

    这些定时器都不共享同一个接口,因此将它们作为依赖项传递是毫无意义的,我已经纠正了这一点在我修改后的代码中。

  2. 如果从逻辑上考虑,Start方法将在实例化MyClassInvoker类,因此如果我将事件绑定在那里它会很有意义。