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:
- 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.
- I passed a Timer object in my previous code, so as to promote testability.
Solutions with explanation
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.
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.