Как отписать все обработчики от события для определенного класса в C #? - PullRequest
32 голосов
/ 15 января 2009

Основная посылка:

У меня есть комната, в которой публикуется событие, когда аватар «входит» во все аватары в комнате. Когда аватар покидает комнату, я хочу удалить все подписки на эту комнату.

Как мне лучше всего отписать аватар от всех событий в комнате, прежде чем я добавлю аватар в новую комнату и подпишусь на события новой комнаты?

Код выглядит примерно так:

class Room
{
   public event EventHandler<EnterRoomEventArgs> AvatarEntersRoom;
   public event EvnetHandler<LeaveRoomEventArgs> AvatarLeavesRoom;
   public event EventHandler<AnotherOfManyEventArgs> AnotherOfManayAvatarEvents;


   public void AddPlayer(Avatar theAvatar)
   {
      AvatarEntersRoom(this, new EnterRoomEventArgs()); 

      AvatarEntersRoom += new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);

      AvatarLeavesRoom += new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);

      AnotherOfManayAvatarEvents += new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);          

   }

}

class Avatar
{
   public void HandleAvatarEntersRoom(object sender, EnterRoomEventArgs e)
   {
       Log.Write("avatar has entered the room");
   }

   public void HandleAvatarLeaveRoom(object sender, LeaveRoomEventArgs e)
   {
       Log.Write("avatar has left room");
   }

   public void HandleAnotherOfManayAvatarEvents(object sender, AnotherOfManyEventArgs e)
   {
       Log.Write("another avatar event has occurred");
   }
}

Ответы [ 4 ]

50 голосов
/ 15 января 2009

У каждого делегата есть метод с именем GetInvocationList(), который возвращает все фактические делегаты, которые были зарегистрированы. Таким образом, предполагая, что тип делегата (или событие) называется скажем MyDelegate, а переменная экземпляра обработчика называется myDlgHandler, вы можете написать:

Delegate[] clientList = myDlgHandler.GetInvocationList();
foreach (var d in clientList)
       myDlgHandler -= (d as MyDelegate);

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

 if(myDlgHandler != null)
  foreach (var d in myDlgHandler.GetInvocationList())
       myDlgHandler -= (d as MyDelegate);
4 голосов
/ 15 января 2009

Вероятно, самый простой способ сделать это - сохранить все ваши подписанные события для аватара у ArrayList делегатов на события.

Когда аватар покидает комнату, просто переберите список делегатов, выполняющих стандартное удаление (-=).

4 голосов
/ 15 января 2009

Что-то не так со стандартным удалением?

public void RemovePlayer(Avatar theAvatar) {
 AvatarEntersRoom -= new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);

}

EDIT

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

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

1 голос
/ 15 января 2009

вы можете запустить на всех подписчиках мероприятия с:

_Event.GetInvocationList()

и удалите каждый обработчик событий.

Delegate[] subscribers = myEvent.GetInvocationList();

for(int i = 0; i < subscribers.Length; i++)    
{    
    myEvent -= subscribers[i] as yourDelegateType;   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...