是否有一种方法可以判断事件处理程序是否已添加到对象?我正在序列化一个对象列表进入/退出会话状态,这样我们就可以使用基于SQL的会话状态…当列表中的对象发生属性更改时,需要标记它,这是事件处理程序之前适当处理的。但是现在当对象被反序列化时,它不会得到事件处理程序。

出于些许烦恼,我只是将事件处理程序添加到访问对象的Get属性中。它现在被调用了,这很好,除了它被调用了5次所以我认为每次对象被访问时处理程序都会被添加。

忽略它确实足够安全,但我宁愿通过检查是否已经添加了处理程序来使它更干净,因此我只这样做一次。

这可能吗?

编辑:我没有必要完全控制添加什么事件处理程序,所以仅仅检查null是不够的。


如果这是唯一的处理程序,您可以检查事件是否为空,如果不是,则添加了处理程序。

我认为您可以安全地使用处理程序对事件调用-=,即使它没有被添加(如果没有,您可以捕获它)—以确保在添加之前它不在那里。


EventHandler.GetInvocationList().Length > 0

正如@Telos提到的,在定义类之外,只能在a +=或a -=的左侧使用EventHandler。因此,如果能够修改定义类,则可以提供一个方法来执行检查,检查事件处理程序是否为空——如果为空,则没有添加事件处理程序。如果不是,那么你可以循环其中的值 Delegate.GetInvocationList。如果一个等于你想要添加为事件处理程序的委托,那么你就知道它在那里。

public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{   
    if ( this.EventHandler != null )
    {
        foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
        {
            if ( existingHandler == prospectiveHandler )
            {
                return true;
            }
        }
    }
    return false;
}

这可以很容易地修改为“如果它不存在,则添加处理程序”。如果您无法访问公开事件的类的内部结构,则可能需要像@Lou Franco所建议的那样探索-=和+=。

但是,您最好重新检查您调试和退役这些对象的方式,看看您是否不能自己找到跟踪这些信息的方法。


这个例子展示了如何使用GetInvocationList()方法来检索已添加的所有处理程序的委托。如果要查看是否添加了特定的处理程序(函数),则可以使用array。

public class MyClass
{
  event Action MyEvent;
}

...

MyClass myClass = new MyClass();
myClass.MyEvent += SomeFunction;

...

Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example

Console.WriteLine(handlers[0].Method.Name);//prints the name of the method

您可以检查委托的Method属性上的各种属性,以查看是否添加了特定的函数。

如果您要查看是否只有一个附加,您可以只测试为空。


如果我对你的问题理解正确,你可能有更大的问题。你说过其他对象可能订阅这些事件。当对象被序列化和反序列化时,其他对象(您无法控制的对象)将失去它们的事件处理程序。

如果您不担心这个问题,那么保持对事件处理程序的引用就足够了。如果您担心其他对象丢失其事件处理程序的副作用,那么您可能需要重新考虑缓存策略。


我最近遇到了类似的情况,我只需要为一个事件注册一次处理程序。我发现你可以安全地先注销,然后再次注册,即使处理程序根本没有注册:

myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;

请注意,每次注册处理程序时都这样做将确保处理程序只注册一次。 听起来对我来说是一个很好的练习:)


我同意阿尔夫的回答,但稍加修改, 使用,

           try
            {
                control_name.Click -= event_Click;
                main_browser.Document.Click += Document_Click;
            }
            catch(Exception exce)
            {
                main_browser.Document.Click += Document_Click;
            }

对我来说,唯一有效的方法是创建一个布尔变量,当我添加事件时,我将其设置为true。然后我问:如果变量为假,我就添加事件。

bool alreadyAdded = false;

这个变量可以是全局的。

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}