Frage

I have a situation here, where by I need a timer in my class which invokes some method based on time interval.

On normal scenarios I would have instantiated timer and configured it in the constructor itself. But I want to do it in dependency injection style. Passing the timer in the constructor is easy, but in order to bind a method to its OnTimeElapsed is tricky, should the factory instantiating the class, configure this timer? how should I go ahead without violating dpendency injection principles.

Thanks

Edit1

Ok, let me rephrase what I actually wanted to ask.

  1. According to videos posted by Misko
  2. during his other talks (never test Your framework: .net framework here)
  3. in his code review guide that anything done beyond field assignments in the constructor is considered bad.

My main goal of achieving dependency injection is that I need to unit test that on a particular elapsed time whether a method has been called or not.

So my question is: where should I bind OnTimerElapsed event? Am I actually trying to test the timer here? I seem to get lost here

kindly help.

War es hilfreich?

Lösung 2

Posting an answer for newcomers to Dependency Injection.

My previous problematic code goes here:

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();
    }
}

After revamping the code it looks like:

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();
    }
}

After thinking intuitively about the problem, I am posting an analysis:

  1. As per the links posted in my own question, never do more work in constructor besides simple assigning. I was actually binding an event handler in the constructor. I cannot comment as of now what could have been the implications if I did it this way.
  2. I passed a Timer object in my previous code, so as to promote testability.

Solutions with explanation

  1. By passing Timer as a dependency, I was trying to give an interface to mock a .Net Timer BCL in order to unit Test as well as give substitution. There are at present three types of Timers in .Net

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

    none of these timers share the same interface, so it is pointless to pass them as a dependency, which I have corrected in my revamped code.

  2. If thought logically, Start method would be called after instantiating MyClassInvoker class, so if I put the event binding there it would make much sense.

Andere Tipps

If your question is, that you want to dependency inject a timer that you can later bind an event to, it should be simple.

Just create your Timer class to follow an ITimer interface and create methods on it to do the actions you want.

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);
}

In this case, you have a calendar application, and you want your application to have a timer. But you don't care how the timer works, or even what kind of timer (maybe you want a timer that works on minutes, or hours, or it works some other way). All you know is that you want a timer, so you dependency inject one.

You have to create an interface, that defines what the timer will do, because although it doesn't care about which timer you use, it does care about the capabilities of the timer. In our case, the timer can do one thing - set an event to occur after a certain interval.

So we inject the timer, but in order to be able to use it, or set it up, we use the interface to define methods. We never know how it works internally - we don't even know it has an OnElapsedEvent, and we don't care. Leave that to the creator of the timer, we just want one method that will do the task, and that's what the code above demonstrates.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top