【发布时间】:2011-01-25 12:51:52
【问题描述】:
在我的 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()
在我的方法中,我正在停止计时器并更改计时器间隔。那是我得到异常的地方。
我已经阅读了一些关于这个错误的信息,但是即使在 .NET 3.5 中也有这个错误是否仍然可以通过?
我该如何解决?我应该在停止后更新计时器对象并将间隔设置为新对象吗?我正在使用 GC.KeepAlive(dataTimer);
编辑: 我发现了一些关于这个问题的其他问题:
*我找到了一个链接 http://www.kbalertz.com/kb_842793.aspx 基本上,一旦您停止计时器,内部 System.Threading.Timer 可用于垃圾收集, 有时会导致过去的事件不发生,或者有时 导致已释放的引用异常。 虽然文章中没有描述,但我的解决方案是 每次定时器要创建一个新的定时器 停止并重新添加经过的事件。效率不高,但很简单, 对我来说不是处理器方面的问题。 这完全解决了我的问题。 为所有回复的人干杯。*
但我很困惑为什么错误仍然存在,我需要确保重新添加计时器是个好主意...
导致错误的代码:
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();
}
从 SerialPortDataReceived 事件调用函数:
private void SerialPortDataReceived(object sender, EventArgs e)
{
StartAsyncResponseTimer();
}
定时器在调用更改间隔之前已停止。
计时器是我班级的私有字段:
private Timer asyncResponseTimer = new Timer();
编辑:应用程序已经连续运行了几个月,这是我第一次遇到这个异常!
我的处置模式:
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();
}
}
【问题讨论】:
-
给我们您的代码以及错误信息。我的猜测是你正在使用一个“使用”块,当你不应该这样做时,它会在完成时自动处理一些东西。我们会查看您的代码并尝试告诉您。
-
我在使用计时器时的价值在于在某处保留对它们的引用(例如私有字段或计时器集合),以便我知道仍有引用。这样我就知道他们不会在我想之前被 GCed。尽管您这样做了,但您当然必须确保在完成计时器对象后删除该引用。
-
我有定时器被引用为类的私有成员。
-
引用的错误很久以前就修复了。查看 Dispose() 调用和 using 语句的代码。区分代码的已知工作版本应该会有所帮助。
-
创建一个新项目并构建一个重现错误并显示该代码的基本项目。