私のWindowsサービスアプリケーションでは、タイマーをたくさん使用しています。私はSystem.Timersだけを使用しています。 私は前にこの問題を経験したことがありませんが、突然、私はこの例外だ:私はタイマーを停止し、タイマー間隔を変更しています私の方法では.NET 3.5 C#System.TimerでのバグSystem.ObjectDisposedException:廃棄されたオブジェクトにアクセスできない
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();
EDIT:
タイマーは、私のクラスのプライベートなフィールドであるアプリケーションは、行の数ヶ月のために実行されている、これは私がこの例外を得た最初の時間です!
マイ処分パターン:
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();
}
}
エラーメッセージと同様に、コードを入力してください。私の推測では、あなたがしてはいけないときに終了したら何かを自動的に破棄する「使用する」ブロックを使用していると思います。私たちはあなたのコードを見て、あなたに教えようとします。 – Chris
タイマーを使うときの私のテクニックの価値は、どこかで(例えば私的なフィールドやタイマーの集まり)参照を保持して、参照があることを知ることです。私がしたいと思う前に彼らがGCedされないことを私が知っている方法。もちろん、タイマーオブジェクトの処理が完了したら、その参照を削除する必要があります。 – Chris
私はタイマーをクラスのプライベートメンバーとして参照しています。 – Simon