4

追加されたすべてのイベントを取得する方法を考えて、PC の前に座っています。イベントをよりよく理解するために、 AC# Bedtime Storyを含むいくつかの記事を読んだところです。しかし、イベントが発生した場合に実行されるメソッド/デリゲートのリストを取得する方法がわかりませんでした。実際、私の場合、メソッド/デリゲートが特定のイベントに割り当てられているかどうかを知っていれば十分です。例:私は(キーボード/マウスフック用に)使用していますイベントイベントがnullでないGma.UserActivityMonitorかどうかを知りたいです。HookManager.KeyUpnull の場合、デリゲートのシャウトが追加されます。私の場合、これは \/

HookManager.KeyUp += new KeyEventHandler(HookManager_KeyUp);

編集

サンプルコード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using Gma.UserActivityMonitor;

namespace EventTest 
{ 
    public partial class Form1 : Form 
    { 
        public Form1() 
        { 
            InitializeComponent();             
            HookManager.KeyUp += new KeyEventHandler(HookManager_KeyUp);
            Delegate[] a = GetEventSubscribers(button1, "Click");
            label1.Text = a[0].Method.ToString();
        } 
        void HookManager_KeyUp(object sender, KeyEventArgs e) 
        {         
            /* Do something*/     
        } 
        bool NoEventAttached() 
        { 
            return false; 
        }

        public static Delegate[] GetEventSubscribers(object target, string eventName) 
        { 
            Type t = target.GetType(); 
            var eventInfo = t.GetEvent(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); 

            do 
            { 
                FieldInfo[] fia = t.GetFields(
                    BindingFlags.Static | 
                    BindingFlags.Instance | 
                    BindingFlags.NonPublic); 

                foreach (FieldInfo fi in fia) 
                { 
                    if (fi.Name == eventName) 
                    { 
                        Delegate d = fi.GetValue(target) as Delegate;                         
                        if (d != null)                         
                            return d.GetInvocationList(); 
                    } 
                    else if (fi.FieldType == typeof(EventHandlerList)) 
                    { 
                        ----> var obj = fi.GetValue(target) as EventHandlerList; 
                        var eventHandlerFieldInfo = obj.GetType().GetField("head", BindingFlags.Instance | BindingFlags.NonPublic); 
                        do 
                        { 
                            var listEntry = eventHandlerFieldInfo.GetValue(obj); 
                            var handler = listEntry.GetType().GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic); 
                            if (handler != null) 
                            { 
                                var subD = handler.GetValue(listEntry) as Delegate; 
                                if (subD.GetType() != eventInfo.EventHandlerType) 
                                { 
                                    eventHandlerFieldInfo = listEntry.GetType().GetField("next", BindingFlags.Instance | BindingFlags.NonPublic); 
                                    obj = listEntry as EventHandlerList; <-----------
                                    continue; 
                                } 
                                if (subD != null) 
                                { 
                                    return subD.GetInvocationList(); 
                                } 
                            } 
                        } 
                        while (eventHandlerFieldInfo != null);                 
                    } 
                } 
                t = t.BaseType; 
            } while (t != null);          
            return new Delegate[] { }; 
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void button1_MouseClick(object sender, MouseEventArgs e)
        {

        }


    } 
}
4

2 に答える 2

5

このコンソール アプリケーション、特に calling という行に注意してくださいGetInvocationList()。このメソッドは、アタッチされたデリゲートのリストを返します。それぞれDelegateMethodプロパティがあります。各MethodプロパティにはName.

デリゲートはあなたが所有しています

internal class Program
{
    public event EventHandler CheckInvocationList;

    private static void Main(string[] args)
    {
        Program p = new Program();
        p.CheckInvocationList += new EventHandler(p_CheckInvocationList);
        p.Method1();

        Console.WriteLine(string.Join(" | ", p.CheckInvocationList.GetInvocationList().Select(d => d.Method.Name).ToArray()));
    }

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

    public void Method1()
    {
        this.CheckInvocationList += new EventHandler(Program_CheckInvocationList);
    }

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

デリゲートはあなたが所有していません

わかりました、これは少し面倒ですが、必要な答えが得られます。内部実装がEventHandlerList(やや一般的ですが) を使用している場合でも、非常に多くの異なる内部表現が存在する可能性があるため、絶対にすべてのシナリオで機能することを保証することはできません。

ただし、うまくいけば、これはうまくいくでしょう。例でわかるように、BackgroundWorker所有していない特定のイベントの呼び出しリストを取得するためのサンプル クラスとしてクラスを使用しています。

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

internal class Program
{
    private static void Main(string[] args)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.DoWork += new DoWorkEventHandler(worker_DoWork2);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

        Console.WriteLine(string.Join(" | ", GetEventSubscribers(worker, "DoWork").Select(d => d.Method.Name).ToArray()));
    }

    static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        throw new NotImplementedException();
    }

    static void worker_DoWork2(object sender, DoWorkEventArgs e)
    {
        throw new NotImplementedException();
    }

    static void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        throw new System.NotImplementedException();
    }

    public static Delegate[] GetEventSubscribers(object target, string eventName)
    {
        Type t = target.GetType();
        var eventInfo = t.GetEvent(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);

        do
        {
            FieldInfo[] fia = t.GetFields(
                 BindingFlags.Static |
                 BindingFlags.Instance |
                 BindingFlags.NonPublic);

            foreach (FieldInfo fi in fia)
            {
                if (fi.Name == eventName)
                {
                    Delegate d = fi.GetValue(target) as Delegate;
                    if (d != null)
                        return d.GetInvocationList();
                }
                else if (fi.FieldType == typeof(EventHandlerList))
                {
                    dynamic obj = fi.GetValue(target) as EventHandlerList;
                    var eventHandlerFieldInfo = obj.GetType().GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
                    do
                    {
                        var listEntry = eventHandlerFieldInfo.GetValue(obj);
                        var handler = listEntry.GetType().GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
                        if (handler != null)
                        {
                            var subD = handler.GetValue(listEntry) as Delegate;
                            if (subD.GetType() != eventInfo.EventHandlerType)
                            {
                                eventHandlerFieldInfo = listEntry.GetType().GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
                                obj = listEntry;
                                continue;
                            }
                            if (subD != null)
                            {
                                return subD.GetInvocationList();
                            }
                        }
                    }
                    while (eventHandlerFieldInfo != null);
                }
            }

            t = t.BaseType;
        } while (t != null);

        return new Delegate[] { };
    }
}

最後に、コードにかなり大きな変更を加えましたが、これを始めたのはBob Powellのおかげです。

于 2012-09-18T11:55:12.357 に答える
1

HookManager.KeyUpをnullと比較するだけで、答えが得られると思います。

それ以外は、最後に調べてから状況が変わっていない限り(かなり可能です)、イベントに関連付けられている代理人の実際のリストを取得するのはかなり困難です。ただし、値がnullの場合は、デリゲートが関連付けられていないことを示しています。

于 2012-09-18T11:41:47.283 に答える