如何从拥有类外部检查事件处理程序的成员资格?

时间:2015-02-13 13:54:31

标签: c# .net events event-handling

This question询问是否有办法查找代码是否已将自己的事件处理程序添加到事件中。但是,给出的答案只能在拥有该事件的同一个类中进行。 ( Delegate.GetInvocationList 和其他人。)

我想为 AppDomain.CurrentDomain.AssemblyResolve 添加自定义事件处理程序。有没有办法在再次添加之前找出我的自定义处理程序是否已添加? (对于此标准库事件和其他标准库事件。)

如果答案确实是'#34;那是不可能的。"那么请把它作为答案。

2 个答案:

答案 0 :(得分:5)

那是不可能的。

基本上,您对外部事件的唯一操作是"订阅"和"取消订阅"。

现在,您可以在订阅前始终取消订阅。如果指定的处理程序不是事件的处理程序,则取消订阅是无操作。如果你确定总是这样做,那么你肯定只有一个处理程序订阅。这确实意味着你需要小心这样做你订阅的所有 - 所以理想情况下,将代码放在一个地方。

(或者,只需更改您的活动订阅,以便您可以轻松告诉您,您只会订阅一次...)

答案 1 :(得分:1)

可以 ......

您可以使用反射来让所有代表订阅该活动,然后检查他们的名字,看看您的名字是否在那里......

public class Foo
{
    public event EventHandler MyEvent;
}

public class Bar
{
    public static event EventHandler MyStaticEvent;
}

public class Test
{
    public void MyDelegate(object sender, EventArgs e) { }
}

class Program
{
    static void Main(string[] args)
    {
        Foo aFoo = new Foo();
        Test aTest = new Test();
        aFoo.MyEvent += aTest.MyDelegate;

        FieldInfo subscribersReflect = typeof(Foo).GetField("MyEvent", BindingFlags.NonPublic | BindingFlags.Instance);
        Delegate[] subscribers = (subscribersReflect.GetValue(aFoo) as MulticastDelegate).GetInvocationList();

        foreach (var sub in subscribers)
            Console.WriteLine(sub.Method.Name); // MyDelegate

        Bar.MyStaticEvent += aTest.MyDelegate;
        subscribersReflect = typeof(Bar).GetField("MyStaticEvent", BindingFlags.NonPublic | BindingFlags.Static);
        subscribers = (subscribersReflect.GetValue(null) as MulticastDelegate).GetInvocationList();

        foreach (var sub in subscribers)
            Console.WriteLine(sub.Method.Name); // MyDelegate

        Console.ReadLine();
    }
}

...但你真的不应该

任何时候你发现自己想用反射去另一个班级挖掘,尤其是一个你没有来源的课程,而且超级特别是一个框架类,它应该是一个警告信号,表明你做错了。

Jon Skeet的解决方案(取消订阅然后订阅)绝对是您问题的正确解决方案,无论如何都是一个好习惯。正如他所提到的那样,取消订阅未订阅的代表实际上没有任何成本,所以每当您不确定时,请继续并取消订阅。它的设计方式是专门,这样你就可以做到而不是使用反射。