C# 是否已经添加了事件处理程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/136975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:05:35  来源:igfitidea点击:

Has an event handler already been added?

提问by CodeRedick

Is there a way to tell if an event handler has been added to an object? I'm serializing a list of objects into/out of session state so we can use SQL based session state... When an object in the list has a property changed it needs to be flagged, which the event handler took care of properly before. However now when the objects are deserialized it isn't getting the event handler.

有没有办法判断事件处理程序是否已添加到对象中?我正在将对象列表序列化为/退出会话状态,以便我们可以使用基于 SQL 的会话状态... . 但是,现在当对象被反序列化时,它不会获得事件处理程序。

In an fit of mild annoyance, I just added the event handler to the Get property that accesses the object. It's getting called now which is great, except that it's getting called like 5 times so I think the handler just keeps getting added every time the object is accessed.

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

It's really safe enough to just ignore, but I'd rather make it that much cleaner by checking to see if the handler has already been added so I only do so once.

忽略它真的很安全,但我宁愿通过检查处理程序是否已经添加来让它更干净,所以我只这样做一次。

Is that possible?

那可能吗?

EDIT: I don't necessarily have full control of what event handlers are added, so just checking for null isn't good enough.

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

采纳答案by Blair Conrad

From outside the defining class, as @Telos mentions, you can only use EventHandler on the left-hand side of a +=or a -=. So, if you have the ability to modify the defining class, you could provide a method to perform the check by checking if the event handler is null- if so, then no event handler has been added. If not, then maybe and you can loop through the values in Delegate.GetInvocationList. If one is equal to the delegate that you want to add as event handler, then you know it's there.

从定义类的外部,正如@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;
}

And this could easily be modified to become "add the handler if it's not there". If you don't have access to the innards of the class that's exposing the event, you may need to explore -=and +=, as suggested by @Lou Franco.

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

However, you may be better off reexamining the way you're commissioning and decommissioning these objects, to see if you can't find a way to track this information yourself.

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

回答by Lou Franco

If this is the only handler, you can check to see if the event is null, if it isn't, the handler has been added.

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

I think you can safely call -= on the event with your handler even if it's not added (if not, you could catch it) -- to make sure it isn't in there before adding.

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

回答by benPearce

EventHandler.GetInvocationList().Length > 0

回答by Jason Hymanson

This example shows how to use the method GetInvocationList() to retrieve delegates to all the handlers that have been added. If you are looking to see if a specific handler (function) has been added then you can use array.

此示例说明如何使用 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

You can examine various properties on the Method property of the delegate to see if a specific function has been added.

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

If you are looking to see if there is just one attached, you can just test for null.

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

回答by CodeChef

If I understand your problem correctly you may have bigger issues. You said that other objects may subscribe to these events. When the object is serialized and deserialized the other objects (the ones that you don't have control of) will lose their event handlers.

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

If you're not worried about that then keeping a reference to your event handler should be good enough. If you are worried about the side-effects of other objects losing their event handlers, then you may want to rethink your caching strategy.

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

回答by alf

I recently came to a similar situation where I needed to register a handler for an event only once. I found that you can safely unregister first, and then register again, even if the handler is not registered at all:

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

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

Note that doing this every time you register your handler will ensure that your handler is registered only once. Sounds like a pretty good practice to me :)

请注意,每次注册处理程序时都执行此操作将确保您的处理程序仅注册一次。对我来说听起来是一个很好的练习:)

回答by Software_developer

i agree with alf's answer,but little modification to it is,, to use,

我同意 alf 的回答,但几乎没有修改,使用,

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

回答by Xtian11

The only way that worked for me is creating a Boolean variable that I set to true when I add the event. Then I ask: If the variable is false, I add the event.

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

bool alreadyAdded = false;

This variable can be global.

这个变量可以是全局的。

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