Как получить объект делегата из EventInfo? - PullRequest
9 голосов
/ 24 сентября 2010

Мне нужно получить все события из текущего класса и выяснить методы, которые подписываются на него. Здесь я получил несколько ответов о том, как это сделать , но я не знаю, как мне получить delegate, когда у меня есть только EventInfo.

var events = GetType().GetEvents();

foreach (var e in events)
{
    Delegate d = e./*GetDelegateFromThisEventInfo()*/;
    var methods = d.GetInvocationList();
}

Можно ли получить делегата с EventInfo?Как?

Ответы [ 3 ]

12 голосов
/ 24 сентября 2010

Оператор var events = GetType().GetEvents(); возвращает список EventInfo объектов, связанных с текущим типом, а не с текущим экземпляром как таковым. Таким образом, объект EventInfo не содержит информации о текущем экземпляре и, следовательно, он не знает о подключенных делегатах.

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

public class MyClass
{
    public event EventHandler MyEvent;

    public IEnumerable<MethodInfo> GetSubscribedMethods()
    {
        Func<EventInfo, FieldInfo> ei2fi =
            ei => this.GetType().GetField(ei.Name,
                BindingFlags.NonPublic |
                BindingFlags.Instance |
                BindingFlags.GetField);

        return from eventInfo in this.GetType().GetEvents()
               let eventFieldInfo = ei2fi(eventInfo)
               let eventFieldValue =
                   (System.Delegate)eventFieldInfo.GetValue(this)
               from subscribedDelegate in eventFieldValue.GetInvocationList()
               select subscribedDelegate.Method;
    }
}

Так что теперь ваш код вызова может выглядеть так:

class GetSubscribedMethodsExample
{
    public static void Execute()
    {
        var instance = new MyClass();
        instance.MyEvent += new EventHandler(MyHandler);
        instance.MyEvent += (s, e) => { };

        instance.GetSubscribedMethods()
            .Run(h => Console.WriteLine(h.Name));
    }

    static void MyHandler(object sender, EventArgs e)
    {
        throw new NotImplementedException();
    }
}

Вывод выше:

MyHandler
<Execute>b__0

Я уверен, что вы можете поиграться с кодом, если хотите вернуть делегат, а не информацию о методе и т. Д.

Надеюсь, это поможет.

3 голосов
/ 17 декабря 2012

В моем случае значение поля (класс ToolStripMenuItem, поле EventClick), к сожалению, имеет тип объекта, а не делегат.Мне пришлось прибегнуть к свойству Events, которое Лес упомянул в своем ответе, так, как я получил от здесь .Поле EventClick в этом случае содержит только ключ EventHandlerList, хранящийся в этом свойстве.

Некоторые другие замечания:

  • Правило fieldName = "Event" + eventName, которое я использовал, не будет работатькаждый случай.К сожалению, нет общего правила связывать имя события с именем поля.Вы можете попытаться использовать статический словарь для сопоставления, подобный этой статье .
  • Я никогда не совсем уверен насчет BindingFlags.В другом сценарии вам, возможно, придется настроить их.

    /// <summary>
    /// Gets the EventHandler delegate attached to the specified event and object
    /// </summary>
    /// <param name="obj">object that contains the event</param>
    /// <param name="eventName">name of the event, e.g. "Click"</param>
    public static Delegate GetEventHandler(object obj, string eventName)
    {
        Delegate retDelegate = null;
        FieldInfo fi = obj.GetType().GetField("Event" + eventName, 
                                               BindingFlags.NonPublic | 
                                               BindingFlags.Static |
                                               BindingFlags.Instance | 
                                               BindingFlags.FlattenHierarchy |
                                               BindingFlags.IgnoreCase);
        if (fi != null)
        {
            object value = fi.GetValue(obj);
            if (value is Delegate)
                retDelegate = (Delegate)value;
            else if (value != null) // value may be just object
            {
                PropertyInfo pi = obj.GetType().GetProperty("Events",
                                               BindingFlags.NonPublic |
                                               BindingFlags.Instance);
                if (pi != null)
                {
                    EventHandlerList eventHandlers = pi.GetValue(obj) as EventHandlerList;
                    if (eventHandlers != null)
                    {
                        retDelegate = eventHandlers[value];
                    }
                }
            }
        }
        return retDelegate;
    }
    
3 голосов
/ 24 сентября 2010

Подобно Enigmativity , список вызовов можно найти для других классов, а не только для текущего класса ...

    private void testit()
    {
        WithEvents we = new WithEvents();
        we.myEvent += new EventHandler(we_myEvent);
        we.myEvent += new EventHandler(we_myEvent2);

        foreach (EventInfo ev in we.GetType().GetEvents())
        {
            FieldInfo fi = we.GetType().GetField(ev.Name, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
            Delegate del = (Delegate)fi.GetValue(we);
            var list = del.GetInvocationList();
            foreach (var d in list)
            {
                Console.WriteLine("{0}", d.Method.Name);
            }
        }
    }

    void we_myEvent(object sender, EventArgs e)
    {
    }
    void we_myEvent2(object sender, EventArgs e)
    {
    }


public class WithEvents
{
    public event EventHandler myEvent;
}

..., пока обработчики событийобъявлен в классе, как мы видим выше.Но рассмотрим класс Control , в котором EventHandlerList хранится в свойстве «Events», и каждое имя поля события начинается с «Event», за которым следует имя события.Затем есть производные от Form классы, которые, кажется, управляют событиями, но по-разному.Пища для размышлений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...