Как получить подписчиков мероприятия?
Мне нужно скопировать подписчиков одного события на другое событие. Могу ли я получить подписчиков события (например, MyEvent [0], возвращающего делегата)?
Если это невозможно, я бы использовал add accessor для добавления делегатов в список. Будет ли это лучшим решением?
Ответы
Ответ 1
События/делегаты С# являются многоадресными, поэтому делегат сам по себе является списком. Изнутри класса, чтобы получить отдельных абонентов, вы можете использовать:
if(field != null) { // or the event-name for field-like events
// or your own event-type in place of EventHandler
foreach(EventHandler subscriber in field.GetInvocationList())
{
// etc
}
}
Однако, чтобы назначить все сразу, просто используйте + = или прямое назначение:
SomeType other = ...
other.SomeEvent += localEvent;
Ответ 2
Если событие одно из опубликованных другим классом, вы не можете - по крайней мере, не надежно. Хотя мы часто рассматриваем событие как просто переменную делегата, на самом деле это всего лишь пара методов: добавление и удаление (или подписка и отмена подписки).
Если это ваш собственный код, который публикует событие, это легко - вы можете сделать аксессуры добавления/удаления делать все, что вам нравится.
Посмотрите мою статью о событиях и посмотрите, поможет ли это вам. Если нет, просьба дать более подробную информацию о том, что вы хотите сделать, указав, какие биты кода вы можете изменить, а какие нет.
Ответ 3
Обновление (спасибо комментаторам): immointability делегата означает, что клонирование ничего не достигает над назначением.
Когда вы пишете:
myDelegate += AHandler
создается новый новый экземпляр делегата и назначается myDelegate.
Следовательно, приведенный ниже код будет работать точно так же без вызова Clone.
MulticastDelegate (базовый тип) имеет метод Clone.
Чтобы получить доступ к базовому делегату, вам может потребоваться избежать обычного помощника, генерируемого ключевым словом события, и управлять вещами напрямую (пользовательский добавить и удалить аксессоры).
Чтобы показать это:
class Program {
public delegate void MyDelegate(string name);
public event MyDelegate EventOne;
public void HandlerOne(string name) {
Console.WriteLine("This is handler one: {0}", name);
}
public void HandlerTwo(string name) {
Console.WriteLine("This is handler two: {0}", name);
}
public void HandlerThree(string name) {
Console.WriteLine("This is handler three: {0}", name);
}
public void Run() {
EventOne += HandlerOne;
EventOne += HandlerTwo;
Console.WriteLine("Before clone");
EventOne("EventOne");
MyDelegate eventTwo = (MyDelegate)EventOne.Clone();
MyDelegate eventTwo = EventOne;
Console.WriteLine("After clonecopy");
EventOne("EventOne");
eventTwo("eventTwo");
Console.WriteLine("Change event one to show it is different");
EventOne += HandlerThree;
EventOne("EventOne");
eventTwo("eventTwo");
}
static void Main(string[] args) {
(new Program()).Run();
}
}
Ответ 4
Если вам нужно изучить подписчиков события внешнего класса:
EventHandler e = typeof(ExternalClass)
.GetField(nameof(ExternalClass.Event), BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(instanceOfExternalClass) as EventHandler;
if (e != null)
{
Delegate[] subscribers = e.GetInvocationList();
}