Database.OnDataUpdated += new EventHandler(DataBase_OnDataUpdated);
Да, это проблема. Общая диагностика заключается в том, что объект-источник событий переживает объект прослушивателя событий. Или, другими словами, ваш объект формы продолжает прослушивать обновления базы данных даже после того, как он был закрыт пользователем. Обычно это вызывает исключение, наиболее типичный способ обнаружения проблемы, шаблонное исключение ObjectDisposedException, когда обработчик событий пытается обновить удаленные элементы управления. Не совсем ясно, как вам удалось избежать этого режима отказа, убедитесь, что вы не перевели этот режим отказа, скажем, с помощью попытки / улова.
И да, это вызывает проблему с сборщиком мусора. Объект базы данных имеет ссылку на ваш объект формы. Вы дали ему эту ссылку, когда подписались на мероприятие. И использует его снова, позже, когда запускает событие. Необходимо, потому что ваш метод DataBase_OnDataUpdated () является методом экземпляра вашего класса. Сахар синтаксиса C # скрывает этот факт. Фактический код под этим простым оператором назначения события выглядит следующим образом (недействительный код C #):
var delegateObject = new EventHandler(this, &DataBase_OnDataUpdated);
Database.OnDataUpdated = Delegate.Combine(DataBase_OnDataUpdated, delegateObject);
Это скрытый this в вызове конструктора делегата, который передает ссылку на ваш объект формы объекту базы данных. Что хранит его в поле Delegate.Target. Будет использоваться позже, когда он запускает событие.
Таким образом, сборщик мусора неизбежно видит ссылку на ваш объект формы даже после его закрытия. Он находит его обратно в списке вызовов делегата объекта базы данных. Таким образом, объект формы не может быть обработан сборщиком мусора, пока объект базы данных не будет собран сборщиком мусора. Что, судя по вашему вопросу, не произойдет, пока ваша программа не завершится. Вероятно, потому что это статическая переменная.
Есть и другие шаблоны, позволяющие избежать этой проблемы. Вы можете, например, передать ссылку на свою форму классу базы данных, который может сохранить ее в списке активных форм, которые прослушивают уведомления. Он может подписаться на событие Disposed формы, чтобы знать, что форма мертва, и удалить объект из этого списка. Вам также необходимо, чтобы ваша форма реализовывала интерфейс, методы, которые класс базы данных вызывает, когда происходит что-то интересное. Антипод паттерна наблюдателя, в остальном не такой красивый, как использование событий.
Или просто решите проблему, поскольку теперь вы знаете, что ее вызывает. Просто отмените подписку на событие явно:
protected override void OnFormClosed(FormClosedEventArgs e) {
Database.OnDataUpdated -= DataBase_OnDataUpdated;
base.OnFormClosed(e);
}
Обратите внимание на то, что точно такой же код требуется, когда вы подписываетесь на другие источники событий в .NET, которые переживают своих слушателей. Как события, вызванные SystemEvents и Application.Idle
person
Hans Passant
schedule
14.07.2013
Dispose
? - person   schedule 14.07.2013