есть класс в котором набор событий.
из другого класса нужно иметь возможность очистить список делегатов,
назначенных на это события функцией типа
RemoveAllHandlerFromEvent(string ANameEvent)
{
// удаляем из события по имени ANameEvent
// все назначенные обработчики
}
или
RemoveAllHandlerFromEvent(Delegate ANameEvent)
{
// удаляем из события ANameEvent
// все назначенные обработчики
}
самый простой способ это указать все возможные навешенные обработчики,
ведь я же подключал события сам.. но их много, и событий тоже..
есть же вариант как это сделать масштабируемо.
у меня было два варианта
1. через Reflection получить список EventInfo[], далее получить доступ
к событию и список MethodInfo[]
однако, получив скажем событие Е через Reflection, а должен буду
написать
E -= M; //M = метод который может быть назначен на событие..
но КАК получить это через Reflection непонятно..
вызвать методы можно через вызов Invoke, а удалить -= нельзя..
плюс такого подхода в том что он универален и позволяет в любом классе
удалить все назначенные методы
2. в описании событий использовать дополнительный список для хранения
всех делегатов примерно вот так
(за точный синтаксис не ручаюсь, но идейно так):
Здравствуйте, <Аноним>, Вы писали:
А>есть класс в котором набор событий. А>из другого класса нужно иметь возможность очистить список делегатов, А>назначенных на это события функцией типа
…
Если класс, от событий которого надо отписаться, разрабатываешь ты сам и не страшно добавить в него некоторую для этого функциональность (судя по-примерам, такое возможно), то почему бы не сделать так:
namespace ConsoleApplication1
{
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args) {
Test t = new Test();
t.Event += delegate { Debug.Print("Test Handler!"); };
t.FireEvent();
t.ClearEvent();
t.FireEvent();
}
}
class Test
{
public event EventHandler Event;
internal void FireEvent() {
if(Event != null) {
Event(this, EventArgs.Empty);
}//if
}
internal void ClearEvent() {
Event = null;
}
}
}
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[2]: как удалить из события все делегаты?
От:
Аноним
Дата:
03.10.06 17:55
Оценка:
Здравствуйте, _FRED_, Вы писали:
А>>Если класс, от событий которого надо отписаться, разрабатываешь ты сам и не страшно добавить в него некоторую для этого функциональность (судя А>>по-примерам, такое возможно), то почему бы не сделать так:
Точно! можно же просто занулить событие.. !
а я все от с++ и дельфи не могу отойти.. если создал — то нужно обязательно удалить.
спасибо!
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, _FRED_, Вы писали:
А>>>Если класс, от событий которого надо отписаться, разрабатываешь ты сам и не страшно добавить в него некоторую для этого функциональность (судя А>>по-примерам, такое возможно), то почему бы не сделать так:
А>Точно! можно же просто занулить событие.. ! А>а я все от с++ и дельфи не могу отойти.. если создал — то нужно обязательно удалить.
а можно еще так:
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.Event += delegate { Console.WriteLine("Test Handler!"); };
t.FireEvent();
t.ClearEvent();
t.FireEvent();
}
}
class Test
{
public event EventHandler Event;
internal void FireEvent()
{
if(Event != null)
{
Event(this, EventArgs.Empty);
}//if
}
internal void ClearEvent()
{
foreach(EventHandler eh in Event.GetInvocationList())
Event -= eh;
}
}
Тот кто знает не говорит, тот кто говорит не знает.
согласен, но это заставляет перелопатить весь код с событиями.
Есть ведь способ написать одну процедуру для всех событий сразу?
типа
//получаем событие по строкеpublic void RemoveHandlersFromEvent(string ANameEvent)
{
//получаем список всех событий
Type t = typeof(TOLAPGrid);
EventInfo[] EI = t.GetEvents();
foreach (EventInfo E in EI)
{
// нашли нужное событиеif (E.Name == ANameEvent)
{
//могу удалить делегата из события:
E.RemoveEventHandler( событие, делегат);
//могу получить метод для удаления методов:
MethodInfo MI = E.GetRemoveMethod();
//и вызвать его
MI.Invoke(this, new object[1]);
}
}
}
как это не смешно, но дальше ступор и не понимаю где взять ссылку на найденное событие
и ссылку на делегат, который в этом событии есть. Не возможность запустить делегат события методом
invoke, а подствить его в конструкцию
Здравствуйте, ppti, Вы писали:
P>Есть ведь способ написать одну процедуру для всех событий сразу? P>типа
P>//получаем событие по строке
…
P>//получаем список всех событий
…
P>// нашли нужное событие
…
P>//могу удалить делегата из события:
P>//могу получить метод для удаления методов … и вызвать его
P>как это не смешно, но дальше ступор и не понимаю где взять ссылку на найденное событие P>и ссылку на делегат, который в этом событии есть. Не возможность запустить делегат события методом P>invoke, а подствить его в конструкцию
P>Event -= eh
В том-то и песня, что событие — EventInfo (как и свойство-PropertyInfo и метод-MethodInfo) — это (я своими словами, уж как умею ) интерфейсная надстройка, только лишь декларация некоей операции. В подовляющем большинстве случаев событие (*) связано с изменением поля класса, в котором оно (событие) объявлено. Это поле (**) имеет тип делегата, того же, что задан при объявлении события. (Как, например, свойство связано с изменением некоторого поля класса).
Проблема из-за того, что декларативно нигде не указана связь между событием (*) и полем-делегатом (**) (как, например, между свойством и полем, которое оно представляет) и из-за этого _невозможно решить твою задачу тем путём, что ты привёл (по имени события обнулить делегат), если не знать заранее, каким образом и где класс хранит подписчиков.
Например, если в моём примере класса Test объявить событие так:
то поле делегата (**), о котором я говорил, не будет создано компилятором и заранее вообще невозможно предугадать, что присходит при подписке и отписки от события.
Правда, есть возможность решить задачу отписки от всех событий некоего класса, если этот класс работает с событиями так, как, например, System.ComponentModel.Component — с помощью System.ComponentModel.EventHandlerList. Тогда, добравшись до свойства, наподобии Component.Events (что возможно через Reflection) надо у того (у этого свойства, до которого добрались) вызвать Dispose().
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, desco, Вы писали:
D>Здравствуйте, ppti, Вы писали:
В свое время тоже бился над этим вопросом. В приведенных выше примерах есть один недостаток, можно забыть отцепить обработчик и в итоге — утечка памяти. Мы обсуждали уже эту тему как-то, могу найти. Там предлагали решение на WealReference, однако, не очень удачное. Интересно, можно ли именно для этих целей придумать паттерн какой-нибудь на все случаи жизни...