Sim*_*mon 6 .net c# exception timer
在我的Windows服务应用程序中,我经常使用计时器.我只使用System.Timers.我以前从未遇到过这个问题,但突然间我得到了这个例外:
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()
Run Code Online (Sandbox Code Playgroud)
在我的方法中,我停止计时器,并更改计时器间隔.那是我得到例外的地方.
我已经阅读了一些关于这个bug的内容,但是即使在.NET 3.5中也存在这个bug仍然是可行的吗?
我如何解决它?我应该在停止后更新计时器对象并将间隔设置为新对象吗?我正在使用GC.KeepAlive(dataTimer);
编辑: 我发现了一些关于这个问题的其他问题:
*我找到了一个链接 http://www.kbalertz.com/kb_842793.aspx 基本上,一旦你停止计时器,内部System.Threading.Timer就可用于垃圾收集,有时会导致已发生的事件不发生,或者有时导致被处置的引用异常.虽然文章中没有描述,但我的解决方案是每次停止计时器时创建一个新的计时器并重新添加已用事件.效率不高但容易,对我而言不是处理器问题.这完全解决了我的问题.为所有回复的人喝彩.*
但我很困惑为什么这个bug仍然存在,我需要确保重新添加计时器是一个好主意...
导致错误的代码:
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();
}
Run Code Online (Sandbox Code Playgroud)
函数是从SerialPortDataReceived事件调用的:
private void SerialPortDataReceived(object sender, EventArgs e)
{
StartAsyncResponseTimer();
}
Run Code Online (Sandbox Code Playgroud)
定时器在调用更改间隔之前停止.
Timer是我班级的私人领域:
private Timer asyncResponseTimer = new Timer();
Run Code Online (Sandbox Code Playgroud)
编辑:该应用程序连续运行了几个月,这是我第一次遇到这个异常!
我的处置模式:
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();
}
}
Run Code Online (Sandbox Code Playgroud)