In my Windows service app I am using timers a lot. I'm using only System.Timers. I've never experienced this problem before, but suddenly I got this exception:
System.ObjectDisposedException: Cannot access a disposed object.
at System.Threading.TimerBase.ChangeTimer(UInt32 dueTime, UInt32 period)
at System.Threading.Timer.Change(Int32 dueTime, Int32 period)
at System.Timers.Timer.UpdateTimer()
at System.Timers.Timer.set_Interval(Double value)
at MyApp.MySpace.MySpace2.MyClassWithTimer.MethodChangeTimerInterval()
In my method I am stopping the timer, and changing the timer interval. That is the place where I got the exception.
I have read something about this bug but is it still passible to have this bug even in .NET 3.5?
How do I fix it? Should I renew the timer object after stopping and set the interval to a new object? I am using GC.KeepAlive(dataTimer);
Edit: I found some other questions about this problem:
*I found a link http://www.kbalertz.com/kb_842793.aspx Basically as soon as you stop a timer, the internal System.Threading.Timer becomes available for Garbage Collection, sometimes causing the elapsed event not to occur, or sometimes causing a disposed reference exception. Although not described in the article, my solution was to create a new timer every time the timer was to be stopped and re-add the elapsed events. Not efficient but easy, and not a problem processor-wise to me. This has totally solved my problem. Cheers for all who responded.*
But I am confused as to why the bug is still there, and I need to be sure that re-adding the timer is a good idea...
Code that caused the error:
private void StartAsyncResponseTimer()
{
switch (_lastRequestType)
{
case 1:
asyncResponseTimer.Interval = 1000;
break;
case 2:
asyncResponseTimer.Interval = 2000;
break;
case 3:
asyncResponseTimer.Interval = 3000;
break;
default:
asyncResponseTimer.Interval = 10000;
break;
}
asyncResponseTimer.Start();
}
Function was called from SerialPortDataReceived event:
private void SerialPortDataReceived(object sender, EventArgs e)
{
StartAsyncResponseTimer();
}
Timer was stopped before calling changing interval.
Timer is private field of my class:
private Timer asyncResponseTimer = new Timer();
EDIT: The application has been running for several months in a row and this is first time I got this exception!
My dispose pattern:
public class SerialPortCommunication{
...
private void SerialPortDataReceived(object sender, EventArgs e)
{
ReadResponse();
StartAsyncResponseTimer();
}
//used to determine if is recieving response over
private void StartAsyncResponseTimer()
{
switch (_lastRequestType)
{
case 1:
asyncResponseTimer.Interval = 1000;
break;
case 2:
asyncResponseTimer.Interval = 2000;
break;
case 3:
asyncResponseTimer.Interval = 3000;
break;
default:
asyncResponseTimer.Interval = 10000;
break;
}
asyncResponseTimer.Start();
}
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// Dispose managed resources.
}
// Dispose unmanaged resources.
_disposed = true;
Stop();
}
}
~SomeClass()
{
Dispose(false);
}
#endregion
public void Stop()
{
_asyncResponseTimer.Stop();
serialPortManager.ClosePort();
}
}