Интересное событие "Распоряжайся" поведением - PullRequest
3 голосов
/ 15 июля 2009

Я заметил интересное поведение в нашем приложении .NET WinForms. У нас есть форма MDI, в которую добавлено много детей MDI. Эти дочерние формы слушают «широковещательное» событие, которое по сути является призывом обновить себя. Событие объявляется в базовом классе, а события прослушивания добавляются в дочерние формы.

Я заметил, что даже когда эти дочерние формы закрыты, события все еще обрабатываются, если событие явно не удалено в методе Dispose ().

В чем причина этого? Конечно, если форма закрыта, события должны быть отделены / утилизированы? Это потому, что само фактическое событие объявлено во внешнем классе? Это то, что я предполагаю.

Понимание было бы очень полезно.

(с использованием C #, .NET 3.5)

Ответы [ 4 ]

4 голосов
/ 15 июля 2009

Событие, которое все еще находится в области видимости, так как оно находится в главной форме, все еще имеет ссылку на делегат в дочернем окне. Поэтому закрытие окна не приведет к удалению объекта, так как он также все еще находится в области действия этой ссылки. Это очень распространенный способ получить «утечку памяти» в .NET. Также учтите, что, поскольку дочернее окно все еще находится в области видимости, все внутри окна все еще находится в области видимости и также не будет собрано.

Что касается того, почему окно не отсоединяет все обработчики событий при закрытии. Было бы очень странно, если бы это было так. То, что вы закрыли окно, еще не означает, что вы покончили с ним, вы можете открыть его заново, сохранить данные из него для сохранения состояния. Вызов close для окна не имеет специальных свойств по сравнению с вызовом любого другого метода, он не располагает окном, не помечает его для сбора или чего-либо еще.

1 голос
/ 15 июля 2009

Да, это поведение по проекту, которое также является причиной, по которой был получен шаблон WeakEvent .

1 голос
/ 15 июля 2009

Вы правы. Когда вы регистрируете событие, ссылка на вашу форму добавляется в делегат события (в объекте, которому принадлежит это событие). Если вы не удалите регистрацию, ваша форма никогда не будет собирать мусор, потому что по-прежнему есть хотя бы одна ссылка на нее (делегат), и вызовы по-прежнему будут выполняться при возникновении события.

Вы должны всегда следить за тем, чтобы события отписывались, чтобы избежать такой утечки.

0 голосов
/ 15 июля 2009

Ваша подписка на событие "считается" ссылкой на вашу дочернюю форму. (так что ваши дочерние формы также не собираются мусором).

Чтобы увидеть, что происходит, посмотрите справку о делегате. у него есть член с именем Target (типа object), который указывает на подписчика. Итак, у вас еще есть цепочка ссылок:

MDI Parent (издатель событий) -> делегат -> ваша дочерняя форма.

Вы должны очистить подписки на события в Dispose (), иначе ваши дочерние формы никогда не будут иметь права на сборку мусора.

Теперь, если вы посмотрите в Интернете на «слабые реферирующие события», вы найдете множество обходных путей, которые люди опубликовали для определения слабых событий. Вот только один пример: http://www.codeproject.com/KB/cs/weakeventhandlerfactory.aspx

Мне тоже пришлось создать прототип, и я был бы рад поделиться им, если вы этого хотите. Однако мой совет - придерживаться регулярных событий и выполнять очистку в Dispose ().

...