Отписаться от события - PullRequest
4 голосов
/ 21 января 2010

У меня есть следующая функция.

Что он делает, учитывая элемент управления (скорее всего, форму окна), я хочу, чтобы все элементы управления содержали , которые "подчиняются" правилам (функция, проверяющая элементы управления, которые я хочу) подписаться событие (скажем, KeyDown).

Вопрос: как отписаться? Или, что более важно, мне нужно для?

Так как я буду использовать это в событии Load форм в самой форме, мне действительно нужно отписаться, если форма закрывается?

(после небольшого прочтения и небольшого понимания GC я подозреваю, что мне не нужно отписываться, но я не уверен)

//an example of using the function
    private void Form1_Load(object sender, EventArgs e)
    {
        MyEventHandler.CreateKeyDownEventHandlers(this);
    }

//the function
    public static void CreateEventHandlers(Control Ctrl)
    {
        foreach (Control c in Ctrl.Controls)
        {
            //bool Rules(Control) a function that determines to what controls'
            //events to apply the handler 
            if ( Rules(c) )
            {
                c.KeyDown += (s, e) =>
                {
                  // do something
                };

            }

            //a control might be a groupbox so we want their contained
            //controls also
            if (c.Controls != null)
            {
                if (c.Controls.Count > 0)
                {
                    CreateEventHandlers(c);
                }
            }

        }
    }

Это моя первая попытка с событиями, делегатами, анонимными функциями и лямбдами, так что, если я сделал что-то действительно глупое, скажите мне.

Ответы [ 3 ]

2 голосов
/ 21 января 2010

Если вы создаете Форму один раз, а эти обработчики также один раз в начале, тогда вам не нужно ничего чистить.

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

c.KeyDown += (s, e) =>
            {
              // do something
            };

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

2 голосов
/ 21 января 2010

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

Нужно ли вам отписаться: подумайте о времени жизни объекта. Вы создаете анонимные функции в статическом методе и привязываете к элементам управления, которые, как я полагаю, контролируют время жизни.

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

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

0 голосов
/ 21 января 2010

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

yourobject.Yourevent-= YourSubscribedFunction;

Это отменит эту функцию на событии.

О второй части вашего вопроса:

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

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

ClassA a = new ClassA();
using (ClassB b = new ClassB()) // implements IDisposable
{
    b.SubscribeToFoo(a); // b subscribes to FooEvent of ClassA
    a.DoFoo(); // a executes FooEvent
}
GC.Collect(); // Run Garbage Collector just to be sure
a.DoFoo(); // a executes FooEvent

Вызывается подписанный метод ClassB, даже если b удаляется.

...