C#, Как найти, поднято ли событие трубку

Я не думаю, что это было упомянуто, так полагайте, что это

while(i<100)
  FOO(i++);

было бы переведено в

while(i<100)
  do { f(i++); g(i++); } while (0)

уведомление, как i++ оценен дважды макросом. Это может привести к некоторым интересным ошибкам.

37
задан Nick 15 July 2009 в 05:16
поделиться

4 ответа

Ключевое слово C # event создает тонкую иллюзию, заключающуюся в том, что событие имеет список вызовов.

Если вы объявляете событие с помощью ключевое слово C # event , компилятор сгенерирует частный делегат в вашем классе и будет управлять им за вас. Каждый раз, когда вы подписываетесь на событие, вызывается метод add , созданный компилятором, который добавляет обработчик события в список вызовов делегата. Нет явного списка вызовов для события.

Таким образом, единственный способ получить список вызовов делегата - предпочтительно:

  • Использовать отражение для доступа к делегату, созданному компилятором ИЛИ
  • Создать не закрытый делегировать (возможно, внутренний) и реализовать методы добавления / удаления события вручную (это не позволяет компилятору генерировать событие ' s реализация по умолчанию)

Вот пример, демонстрирующий последний метод.

class MyType
{
    internal EventHandler<int> _delegate;
    public event EventHandler<int> MyEvent;
    {
        add { _delegate += value; }
        remove { _delegate -= value; }
    }
}
53
ответ дан 27 November 2019 в 04:04
поделиться

Если соответствующий объект указал ключевое слово события, то единственное, что вы можете сделать, это добавить ( + = ) и удалить ( - = ), не более того.

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

Также имейте в виду, что Операторы + = и - = возвращают новый объект события; они не изменяют существующее.

Почему вы хотите знать, подключено ли конкретное событие? Чтобы избежать многократной регистрации?

Если это так, хитрость заключается в том, чтобы сначала удалить обработчик ( - = ), поскольку удаление обработчика, которого нет, является законным и ничего не делает. Например:

// Ensure we don't end up being triggered multiple times by the event
myObject.KeyEvent -= KeyEventHandler;
myObject.KeyEvent += KeyEventHandler;
64
ответ дан 27 November 2019 в 04:04
поделиться

Вы должны иметь возможность получить список вызовов через "событие". Грубо говоря, это будет что-то вроде ..

public delegate void MyHandler;
public event MyHandler _MyEvent
public int GetInvocationListLength()
{
   var d = this._MyEvent.GetInvocationList(); //Delegate[]
   return d.Length;
}
5
ответ дан 27 November 2019 в 04:04
поделиться

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

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

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string typeName = "ConsoleApplication1.SomeClass, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            string eventName = "SomeEvent";

            Type declaringType = Type.GetType(typeName);
            object target = Activator.CreateInstance(declaringType);

            EventHandler eventDelegate;
            eventDelegate = GetEventHandler(target, eventName);
            if (eventDelegate == null) { Console.WriteLine("No listeners"); }

            // attach a listener
            SomeClass bleh = (SomeClass)target;
            bleh.SomeEvent += delegate { };
            //

            eventDelegate = GetEventHandler(target, eventName);
            if (eventDelegate == null)
            { 
                Console.WriteLine("No listeners"); 
            }
            else
            { 
                Console.WriteLine("Listeners: " + eventDelegate.GetInvocationList().Length); 
            }

            Console.ReadKey();

        }

        static EventHandler GetEventHandler(object classInstance, string eventName)
        {
            Type classType = classInstance.GetType();
            FieldInfo eventField = classType.GetField(eventName, BindingFlags.GetField
                                                               | BindingFlags.NonPublic
                                                               | BindingFlags.Instance);

            EventHandler eventDelegate = (EventHandler)eventField.GetValue(classInstance);

            // eventDelegate will be null if no listeners are attached to the event
            if (eventDelegate == null)
            {
                return null;
            }

            return eventDelegate;
        }
    }

    class SomeClass
    {
        public event EventHandler SomeEvent;
    }
}
13
ответ дан 27 November 2019 в 04:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: