Обработчики событий и анонимные делегаты / лямбда-выражения

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

Предположим, у нас есть событие, которое добавляет либо анонимного делегата, либо лямбда-выражение (для тех счастливчиков, которые могут использовать более новые версии .NET).

SomeClass.SomeEvent += delegate(object o, EventArg e) { /* do something */ };

Я читал, что в прошлом люди забыли о событиях, у которых все еще есть обработчики, предотвращающие сборку мусора. Как можно было бы удалить добавленный обработчик, не просто установив SomeEvent в значение null в классе. Разве это не будет совершенно новым обработчиком?

SomeClass.SomeEvent -= delegate(object o, EventArg e) { /* do something */ };

Я мог видеть сохранение анонимного делегата или лямбда-выражения в переменной. Но это, по крайней мере, мне кажется, лишает нас возможности просто и лаконично добавить обработчик событий.

SomeEventDelegate handler = new SomeEventDelegate(delegate(object o, EventArg e) { /* do something */ });
SomeClass.SomeEvent += handler;
// ... stuff
SomeClass.SomeEvent -= handler;

Опять же, я понимаю, что вы могли бы просто сделать ...

public override Dispose(bool disposing)
{
    _someEvent = null;
    this.Dispose();
}

Но мне интереснее просто удалить из события динамически созданный метод. Надеюсь, кто-нибудь сможет пролить свет на это для меня. Спасибо!


person Nicholas Mancuso    schedule 13.01.2009    source источник
comment
Я имел в виду точно такой же вопрос, и вам удалось его очень четко выразить.   -  person Stefano Ricciardi    schedule 13.05.2011


Ответы (3)


Если у объекта X есть обработчик событий, target которого является объектом Y, то наличие объекта X означает, что объект Y не может быть собран сборщиком мусора. Это не мешает объекту X собираться мусором.

Обычно, когда что-то утилизируют, оно очень скоро превращается в мусор, а это значит, что у вас нет проблем.

Проблема с событиями и сборщиком мусора заключается в том, что вы забыли удалить подписанный обработчик из другого объекта - т.е. у вас есть слушатель, который удален, но никогда не будет собираться мусором, потому что все еще есть ссылка на него из событие в другом объекте.

person Jon Skeet    schedule 13.01.2009
comment
Одна из ловушек обработчиков событий делегата заключается в том, что, хотя они кажутся отключенными от классов, в которых они определены, у вас может быть сгенерированное компилятором закрытие, которое предотвращает сбор экземпляров определяющих классов. - person ; 13.01.2009
comment
Интересный факт: когда ToolStrip становится видимым, он регистрируется в System.UserPreferenceChanged. Поэтому, если вы удалите ToolStrip из его контейнера, не установив для параметра Visible значение false, он никогда не будет удален. Вот почему рано или поздно вам понадобится профилировщик памяти. - person Robert Rossney; 13.01.2009

Я думаю, что проблема в том, что вы, похоже, исходите из предположения, что наличие делегата, назначенного событию объекта, предотвращает его сборку мусора.

Это простое утверждение не соответствует действительности.

С учетом сказанного мнимая проблема исчезает.

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

Как такой процесс построения графиков смог бы прийти к этому объекту?

person AnthonyWJones    schedule 13.01.2009
comment
Утверждение верно, поскольку обработчик событий добавляется во внутренне управляемый список обработчиков. - person Kent Boogaart; 13.01.2009
comment
Если вы не будете осторожны, закрытие может укусить вас под задницу. - person ; 13.01.2009
comment
@Will: Вам действительно нужно объясниться. Может быть, с вашим собственным ответом и примером того, как закрытие может так укусить? - person AnthonyWJones; 13.01.2009
comment
@Kent: У вас есть ссылка на этот список обработчиков, управляемый изнутри? - person AnthonyWJones; 13.01.2009
comment
Поищите здесь кусочек задницы: stackoverflow.com/questions/371109/ - person Benjol; 16.06.2009

Вы не можете.

Точно так же, как вы не можете создать анонимный тип вне его области видимости (за исключением некоторых уловок компилятора).

Вот почему это называется анонимным.

Вы должны где-то сохранить ссылку ... или использовать отражение.

person chakrit    schedule 13.01.2009
comment
Я полагаю, что то же самое и с анонимными объектами. SomeClass.SomeEvent + = новый SomeEventHandler (SomeMethod); нельзя было бы удалить, не установив для события значение null, не так ли? - person Nicholas Mancuso; 13.01.2009