web-dev-qa-db-fra.com

Un gestionnaire d'événements a-t-il déjà été ajouté?

Existe-t-il un moyen de savoir si un gestionnaire d'événements a été ajouté à un objet? Je suis en train de sérialiser une liste d'objets dans/hors de l'état de session afin que nous puissions utiliser l'état de session basé sur SQL ... Lorsqu'un objet de la liste a une propriété modifiée, il doit être signalé, ce que le gestionnaire d'événements prend en charge correctement avant . Cependant, à présent, lorsque les objets sont désérialisés, le gestionnaire d'événement ne s'affiche pas.

Dans une crise de légère contrariété, je viens d'ajouter le gestionnaire d'événements à la propriété Get qui accède à l'objet. Il commence à être appelé maintenant, ce qui est très bien, sauf qu'il s'appelle 5 fois, donc je pense que le gestionnaire continue à être ajouté chaque fois que l'objet est accédé.

C'est vraiment assez sûr pour tout ignorer, mais je préférerais le rendre encore plus propre en vérifiant si le gestionnaire a déjà été ajouté, alors je ne le fais qu'une fois.

Est-ce possible?

EDIT: Je n'ai pas nécessairement le contrôle total sur les gestionnaires d'événements ajoutés. Par conséquent, la vérification de la valeur null ne suffit pas.

171
CodeRedick

En dehors de la classe de définition, comme @Telos le mentionne, vous ne pouvez utiliser EventHandler que du côté gauche d'un += ou un -=. Ainsi, si vous avez la possibilité de modifier la classe de définition, vous pouvez fournir une méthode pour effectuer le contrôle en vérifiant si le gestionnaire d'événements est null. Si c'est le cas, aucun gestionnaire d'événements n'a été ajouté. Si non, alors peut-être et vous pouvez parcourir les valeurs de Delegate.GetInvocationList . Si l'un est égal au délégué que vous souhaitez ajouter en tant que gestionnaire d'événements, alors vous savez qu'il est là.

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

Et cela pourrait facilement être modifié pour devenir "ajoutez le gestionnaire s'il n'est pas là". Si vous n'avez pas accès aux entrailles de la classe qui expose l'événement, vous devrez peut-être explorer -= et +=, comme suggéré par @Lou Franco.

Cependant, vous feriez peut-être mieux de réexaminer la façon dont vous mettez en service et mettez ces objets hors service, pour voir si vous ne pouvez pas trouver un moyen de suivre vous-même ces informations.

117
Blair Conrad

Je suis récemment arrivé à une situation similaire dans laquelle je devais inscrire un gestionnaire pour un événement une seule fois. J'ai constaté que vous pouvez d'abord désenregistrer en toute sécurité, puis vous réinscrire, même si le gestionnaire n'est pas enregistré du tout:

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

Notez que faire cela à chaque fois que vous enregistrez votre gestionnaire garantira que votre gestionnaire ne sera enregistré qu'une seule fois. Cela me semble être une très bonne pratique :)

183
alf

S'il s'agit du seul gestionnaire, vous pouvez vérifier si l'événement est null, sinon, le gestionnaire a été ajouté.

Je pense que vous pouvez appeler en toute sécurité - = sur l'événement avec votre gestionnaire même s'il n'est pas ajouté (sinon, vous pourriez l'attraper) - pour vous assurer qu'il n'est pas présent avant l'ajout.

18
Lou Franco

Cet exemple montre comment utiliser la méthode GetInvocationList () pour récupérer des délégués pour tous les gestionnaires ajoutés. Si vous cherchez à savoir si un gestionnaire spécifique (fonction) a été ajouté, vous pouvez utiliser 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

Vous pouvez examiner différentes propriétés de la propriété Method du délégué pour voir si une fonction spécifique a été ajoutée.

Si vous cherchez à savoir s'il n'y en a qu'un seul, vous pouvez simplement tester null.

6
Jason Jackson

Si je comprends bien votre problème, vous pouvez avoir de plus gros problèmes. Vous avez dit que d'autres objets peuvent souscrire à ces événements. Lorsque l'objet est sérialisé et désérialisé, les autres objets (ceux que vous n'avez pas le contrôle) perdront leurs gestionnaires d'événements.

Si cela ne vous inquiète pas, garder une référence à votre gestionnaire d'événements devrait suffire. Si vous craignez les effets secondaires liés à la perte d'autres gestionnaires d'objets par d'autres objets, vous voudrez peut-être repenser votre stratégie de mise en cache.

4
CodeChef

La seule façon qui a fonctionné pour moi est de créer une variable booléenne que j'ai définie sur true lors de l'ajout de l'événement. Puis je demande: Si la variable est false, j'ajoute l'événement.

bool alreadyAdded = false;

Cette variable peut être globale.

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}
1
Xtian11
EventHandler.GetInvocationList().Length > 0
0
benPearce

je suis d'accord avec la réponse de alf, mais peu de modifications y sont apportées,

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