是否已添加事件处理程序?

时间:2020-03-06 14:45:28  来源:igfitidea点击:

有没有办法判断事件处理程序是否已添加到对象?我正在将对象列表序列化为会话状态或者从会话状态中序列化,以便我们可以使用基于SQL的会话状态...当列表中的对象的属性发生更改时,需要对其进行标记,事件处理程序会在此之前对其进行适当处理。但是现在,当对象反序列化时,它没有获取事件处理程序。

稍有烦恼的是,我只是将事件处理程序添加到访问该对象的Get属性中。现在它被调用了,这很棒,除了它被调用了5次外,所以我认为每次访问该对象时,处理程序都会不断增加。

只需忽略它就足够安全了,但是我宁愿通过检查是否已经添加了处理程序来使其变得更加整洁,所以我只这样做一次。

那可能吗?

编辑:我不一定完全控制添加了什么事件处理程序,因此仅检查null是不够的。

解决方案

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

我认为即使没有添加事件,我们也可以与处理程序一起安全地在事件上调用-=(如果没有,则可以捕获它),以确保在添加事件之前不存在该事件。

EventHandler.GetInvocationList().Length > 0

如@Telos所述,在定义类之外,我们只能在+ =或者-=的左侧使用EventHandler。因此,如果我们能够修改定义的类,则可以通过检查事件处理程序是否为" null"(如果为null)来提供一种执行检查的方法,则无需添加任何事件处理程序。如果没有,那么也许可以遍历中的值
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()检索所有已添加的处理程序的委托。如果要查看是否已添加特定的处理程序(函数),则可以使用数组。

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属性上的各种属性,以查看是否已添加特定功能。

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

如果我正确理解了问题,则可能会遇到更大的问题。我们说其他对象可能订阅了这些事件。当对象被序列化和反序列化时,其他对象(我们无法控制的对象)将丢失其事件处理程序。

如果我们不担心这一点,那么保留对​​事件处理程序的引用就足够了。如果我们担心其他对象失去事件处理程序的副作用,那么我们可能需要重新考虑缓存策略。