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

Cod*_*ick 173 .net c# asp.net

有没有办法判断是否已将事件处理程序添加到对象中?我正在将对象列表序列化为进入/退出会话状态,因此我们可以使用基于SQL的会话状态...当列表中的对象更改了属性时,需要对其进行标记,事件处理程序在此之前正确处理.但是现在当对象被反序列化时,它没有得到事件处理程序.

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

它真的很安全,只是忽略,但我宁愿通过检查处理程序是否已被添加来使它更清洁,所以我只这样做了一次.

那可能吗?

编辑:我不一定完全控制添加什么事件处理程序,所以只检查null是不够的.

alf*_*alf 191

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

myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;
Run Code Online (Sandbox Code Playgroud)

请注意,每次注册处理程序时执行此操作将确保您的处理程序只注册一次.听起来对我来说是一个很好的做法:)

  • 当然.你的意思是它不是线程安全的.但是,这在运行多个线程等时只会是一个问题,这是不常见的.在大多数情况下,为了简单起见,这应该足够好. (23认同)
  • 似乎有风险; 如果在删除处理程序之后触发事件并且在将其添加回之前触发,则将丢失该事件. (8认同)
  • 这困扰我.仅仅因为您当前没有在代码中显式创建线程,这并不意味着没有多个线程,或者以后不会添加它们.只要您(或团队中的其他人,可能在几个月后)添加工作线程或响应UI和网络连接,就会打开高度间歇性丢弃事件的大门. (6认同)
  • 我相信删除和再次添加之间的时间窗口非常小,不太可能存在错过的事件,但是,是的,这仍然是可能的。 (2认同)
  • 如果你使用它来更新 UI 等,那么它是一项微不足道的任务,风险是可以的。如果这是用于网络数据包处理等,那么我不会使用它。 (2认同)

Bla*_*rad 119

从定义类的外部,如@Telos所提到的,你只能在a +=或a 的左侧使用EventHandler -=.因此,如果您能够修改定义类,则可以通过检查事件处理程序是否提供执行检查的方法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;
}
Run Code Online (Sandbox Code Playgroud)

这很容易被修改为"添加处理程序,如果它不存在".如果您无法访问暴露该事件的班级内部,您可能需要探索-=+=按照@Lou Franco的建议进行探索.

但是,您可能最好重新检查调试和停用这些对象的方式,看看您是否找不到自行跟踪此信息的方法.

  • 这不编译,EventHandler只能在+ =或 - =的左侧. (7认同)
  • 在比较代表的相等性时,大多数时候会出现问题.因此,如果要检查完全相同的委托存在,请使用`Delegate.Equals(objA,objB)`.否则单独比较属性,如`if(objA.Method.Name == objB.Method.Name && objA.Target.GetType().FullName == objB.Target.GetType().FullName)`. (3认同)
  • 在进一步解释时删除了投票.SQL状态几乎破坏了整个想法...... :( (2认同)
  • 此代码不适用于WinForm.是严格的ASP.NET吗? (2认同)

Lou*_*nco 18

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

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

  • 一旦事件在其他地方处理,该逻辑就会中断. (3认同)

Jas*_*son 6

此示例显示如何使用方法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
Run Code Online (Sandbox Code Playgroud)

您可以检查委托的Method属性上的各种属性,以查看是否已添加特定功能.

如果您正在查看是否只有一个附加,您可以只测试null.


Xti*_*n11 6

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

bool alreadyAdded = false;
Run Code Online (Sandbox Code Playgroud)

该变量可以是全局的。

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}
Run Code Online (Sandbox Code Playgroud)


Cod*_*hef 5

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

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