Исходя из стека вызовов и предоставленного вами кода, похоже, что вы пытаетесь изменить интервал для уже настроенного таймера. Вам, вероятно, нужно остановить таймер после подтверждения того, что больше нет работы, вместо того, чтобы останавливать его в своем шаблоне утилизации, который, кажется, мешает текущей работе. То есть сначала вы проверяете, есть ли еще работа, если нет, прекращаете прослушивание порта, а затем останавливаете таймер. Это не очень поможет, если я не увижу еще некоторые части кода, такие как обработчики событий, объявление serialPortManager и т. Д.

м сервисном приложении 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 становится доступным для сборки мусора, что иногда приводит к тому, что истекшее событие не происходит, а иногда вызывает исключение удаленного элемента r. Хотя это и не описано в статье, моим решением было создание нового таймера каждый раз, когда таймер должен был быть остановлен, и повторное добавление прошедших событий. Не эффективно, но легко и не проблема для меня. Это полностью решило мою проблему. Приветствия для всех, кто ответил. *

Но я не понимаю, почему ошибка все еще существует, и я должен быть уверен, что повторное добавление таймера - хорошая идея ...

Код, вызвавший ошибку:

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();
    }
}
 Chris25 янв. 2011 г., 13:59
Дайте нам свой код, а также сообщение об ошибке. Я предполагаю, что вы используете блок «using», который автоматически удаляет что-то, когда вы закончите, когда этого не должно быть. Мы посмотрим на ваш код и постараемся рассказать вам, хотя.
 Simon25 янв. 2011 г., 14:07
На меня таймер ссылается как на приватного члена класса.
 s_hewitt04 февр. 2011 г., 22:36
Создайте новый проект и создайте базовый проект, который воспроизводит ошибку и показывает этот код.
 Chris25 янв. 2011 г., 14:01
Моя техника при использовании таймеров стоит того, чтобы где-то хранить ссылки на них (например, частное поле или коллекцию таймеров), чтобы я знал, что ссылки по-прежнему существуют. таким образом я знаю, что они не будут GCed, прежде чем я хочу. Хотя вы, конечно, должны обязательно удалить эту ссылку, когда закончите с объектом таймера.
 Hans Passant25 янв. 2011 г., 15:13
Указанная ошибка была исправлена ​​давно. Проверьте код для вызовов Dispose () ис помощью заявления. Различение известной в работе версии вашего кода должно помочь.

Ответы на вопрос(3)

когда вы запускаете таймер при получении данных через последовательный порт. Что произойдет, если вы получите дополнительные данные о порте до того, как таймер завершит отправку ответа? Судя по опубликованной вами информации, интервал таймера будет изменен и запущен (снова), пока таймер все еще обрабатывает его событие таймера.

Рассматривали ли вы выше сценарий? Таймер автосброс или нет? Когда вы звоните Stop ()?

 Simon26 янв. 2011 г., 16:41
Таймер там, чтобы определить, нет ли полученных данных. Таким образом, таймер перезапускается каждый раз, когда происходит serialPortDataReceived. Если таймер завершит свою работу, я буду знать, что все данные получены, и я могу продолжать отправлять запрос. Таймер имеет по умолчанию AutoReset = true. Я вызываю Stop () только тогда, когда я хочу остановить соединение через последовательный порт, и когда я получил это исключение, Stop () НЕ БЫЛО вызвано. Его в основном вызывается пользователем из пользовательского интерфейса.

я предполагаю, что Windows Server 2003. Когда вы упоминаете, что он работал (почти) два месяца, он напоминает оОшибка 49,7 дней, Это может быть неприменимо к вашему сценарию, если в марте снова не произойдет сбой. :-)

Симптом 2
На компьютере под управлением Windows Server 2003, на котором не установлен ISA Server, аналогичная проблема возникает, когда выполняются следующие условия: Вы повторно вызываете функцию CreateTimerQueueTimer в приложении. Вы устанавливаете указанный период для запуска таймера, который создается функцией CreateTimerQueueTimer.

Приложение работает более 49,7 дней. По истечении 49,7 дней таймер срабатывает сразу, а не после указанного периода. Через несколько минут таймер срабатывает правильно.

KeepAlive () здесь бесполезен, потому что вы объявили таймер на уровне класса - и это хорошо. Нет необходимости останавливать таймер для изменения интервала.

Исходя из стека вызовов и предоставленного вами кода, похоже, что вы пытаетесь изменить интервал для уже настроенного таймера. Вам, вероятно, нужно остановить таймер после подтверждения того, что больше нет работы, вместо того, чтобы останавливать его в своем шаблоне утилизации, который, кажется, мешает текущей работе. То есть сначала вы проверяете, есть ли еще работа, если нет, прекращаете прослушивание порта, а затем останавливаете таймер. Это не очень поможет, если я не увижу еще некоторые части кода, такие как обработчики событий, объявление serialPortManager и т. Д.

что вы получаете данные последовательного порта сразу после того, как вы устранили свой таймер? Это единственное, что приходит мне в голову после опубликованных вами данных! Что ты делаешь в Stop ()! метод внутри Dispose () ????

 Simon26 янв. 2011 г., 14:06
смотрите мои правки пожалуйста.
 Simon26 янв. 2011 г., 14:02
Я никогда не вызываю функцию timer.Dispose (). Мне нужен Stop () для остановки связи через последовательный порт. У меня есть также метод Start (). Когда я избавляюсь от класса SerialPortCommunication, я также останавливал таймер, чтобы предотвратить возникновение после удаления, потому что он находится в другом потоке. Это исключение НЕ было поднято при утилизации. Это произошло в середине связи с последовательным портом. Сброс интервала таймера вызывается каждый раз, когда происходит SerialPortDataReceived ().

Ваш ответ на вопрос