Как получить подписчиков на событие? - PullRequest
27 голосов
/ 21 февраля 2009

Мне нужно скопировать подписчиков одного события на другое событие. Могу ли я получить подписчиков события (например, MyEvent [0], возвращающий делегата)?

Если это невозможно, я бы использовал метод доступа add, чтобы добавить делегатов в список. Это будет лучшим решением?

Ответы [ 4 ]

29 голосов
/ 21 февраля 2009

C # события / делегаты являются многоадресными, поэтому делегатом является сам список. Из класса, чтобы получить отдельных абонентов, вы можете использовать:

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;
13 голосов
/ 21 февраля 2009

Если событие опубликовано другим классом, вы не можете - по крайней мере, ненадежно. Хотя мы часто думаем о событии как о переменной-делегате, на самом деле это просто пара методов: добавить и удалить (или подписаться и отписаться).

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

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

3 голосов
/ 03 ноября 2017

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

EventHandler e = typeof(ExternalClass)
    .GetField(nameof(ExternalClass.Event), BindingFlags.Instance | BindingFlags.NonPublic)
    .GetValue(instanceOfExternalClass) as EventHandler;
if (e != null)
{
    Delegate[] subscribers = e.GetInvocationList();
}
3 голосов
/ 21 февраля 2009

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

Когда пишут:

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");

            <strike>MyDelegate eventTwo = (MyDelegate)EventOne.Clone();</strike>
            MyDelegate eventTwo = EventOne;
            Console.WriteLine("After <strike>clone</strike>copy");
            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();
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...