简体   繁体   English

如何从所属类外部检查事件处理程序的成员身份?

[英]How to check membership of an event handler from outside the owning class?

This question asks if there is a way to find if the code has already added its own event handler to an event. 这个问题问是否有一种方法可以找到代码是否已经将自己的事件处理程序添加到事件中。 However, the answers given only work from inside the same class that own the event. 但是,给出的答案只能在拥有该事件的同一类内部进行。 ( Delegate.GetInvocationList and others.) Delegate.GetInvocationList等。)

I want to add a custom event handler to AppDomain.CurrentDomain.AssemblyResolve . 我想向AppDomain.CurrentDomain.AssemblyResolve添加自定义事件处理程序。 Is there a way to find out if my custom handler is already added before adding it again? 在再次添加我的自定义处理程序之前,是否有办法找出它是否已添加? (For this and other standard library events.) (对于此事件和其他标准库事件。)

If the answer is indeed "That's impossible." 如果答案确实是“那是不可能的”。 then please give that as an answer. 然后请给出答案。

That's impossible. 这不可能。

Basically, the only operations you have with an event from the outside are "subscribe" and "unsubscribe". 基本上,您对外部事件的唯一操作是“订阅”和“取消订阅”。

Now you could always unsubscribe before you subscribe. 现在,您可以随时取消订阅。 Unsubscribing is a no-op if the specified handler isn't already a handler for the event. 如果指定的处理程序还不是该事件的处理程序,则取消订阅是不可操作的。 If you make sure you always do that, then you'll definitely have exactly one handler subscribed. 如果您确保始终这样做,那么您肯定会只订阅了一个处理程序。 It does mean you need to be careful to do that everywhere you subscribe though - so ideally, put that code in one place. 这确实意味着您需要谨慎地订阅的所有位置执行此操作-因此,理想情况下,请将该代码放在一个位置。

(Alternatively, just change your event subscription so that you can easily tell that you'll only ever subscribe once...) (或者,只需更改您的事件订阅,这样您就可以轻松地说出您只会订阅一次...)

You can ... 可以 ...

You can use reflection to get all delegates subscribed to the event and then check their names to see if yours is in there... 您可以使用反射使所有代表都订阅该事件,然后检查其名称以查看您的代表是否在那里...

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();
    }
}

...but you really shouldn't . ...但是你真的不应该

Any time you find yourself tempted to use reflection to go digging around in another class, especially a class you don't have the source for, and super-especially a framework class, that should be a warning signal that you're doing something wrong. 每当您发现自己想使用反射在另一个类中进行挖掘时, 尤其是您没有源的类, 尤其是框架类,这应该是一个警告信号,表明您在做错事。

Jon Skeet's solution (unsubscribe then subscribe) is absolutely the correct solution to your problem, and is a good habit to be in any case. 乔恩·斯凯特(Jon Skeet)的解决方案(先取消订阅,然后订阅) 绝对是解决问题的正确方法,并且在任何情况下都是一个好习惯。 As he mentioned, unsubscribing a delegate that isn't subscribed has effectively no cost whatsoever, so any time you're unsure, go ahead and unsubscribe. 正如他提到的那样,取消订阅未订阅的代表实际上没有任何花费,因此,无论何时您不确定,请继续并取消订阅。 It was designed that way specifically so that you could do that rather than using reflection. 就这样,你能做到这一点,而不是使用反射这样设计的特别

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM