Question

Prenez la classe C # suivante:

c1 {
 event EventHandler someEvent;
}

S'il existe de nombreux abonnements à l'événement someEvent de c1 et que je souhaite les effacer tous, quel est le meilleur moyen d'y parvenir? Notez également que les abonnements à cet événement pourraient être / sont des délégués lambdas / anonymes.

Actuellement, ma solution consiste à ajouter une méthode ResetSubscriptions () à c1 qui définit someEvent sur null. Je ne sais pas si cela a des conséquences invisibles.

Était-ce utile?

La solution

Dans la classe, vous pouvez définir la variable (masquée) sur null. Une référence nulle est la manière canonique de représenter une liste d'appels vide, de manière efficace.

En dehors de la classe, vous ne pouvez pas faire cela - les événements exposent en gros "subscribe". et " se désabonner " et c'est tout.

Il est utile de savoir ce que font en réalité les événements de type champ: ils créent une variable et à la fois. Dans la classe, vous finissez par référencer la variable. Depuis l’extérieur, vous référencez l’événement.

Consultez mon article sur les événements et les délégués pour plus d'informations.

Autres conseils

Ajoutez une méthode à c1 pour définir "un événement" sur null ...

class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = null;}
}
class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = delegate{};}
}

Il vaut mieux utiliser delegate {} que null

Définir l'événement sur null dans la classe fonctionne. Lorsque vous supprimez une classe, vous devez toujours définir l'événement sur null, le GC a des problèmes avec les événements et risque de ne pas nettoyer la classe supprimée si elle comporte des événements en suspens.

La meilleure pratique pour effacer tous les abonnés est de définir la someEvent sur null en ajoutant une autre méthode publique si vous souhaitez exposer cette fonctionnalité à l'extérieur. Cela n'a aucune conséquence invisible. La condition préalable est de ne pas oublier de déclarer SomeEvent avec le mot clé 'event'.

Veuillez consulter le livre - C # 4.0 en bref, page 125.

Quelqu'un ici a proposé d'utiliser la méthode Delegate.RemoveAll . Si vous l'utilisez, l'exemple de code peut suivre le formulaire ci-dessous. Mais c'est vraiment stupide. Pourquoi ne pas simplement SomeEvent = null dans la fonction ClearSubscribers () ?

   public void ClearSubscribers ()
    {
          SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);// Then you will find SomeEvent is set to null.
    }

Vous pouvez y parvenir en utilisant les méthodes Delegate.Remove ou Delegate.RemoveAll.

Commentaire ennuyeux conceptuel prolongé.

Je préfère utiliser le mot "gestionnaire d'événements". au lieu de " événement " ou "délégué". Et utilisé le mot " événement " pour d'autres choses. Dans certains langages de programmation (VB.NET, Object Pascal, Objective-C), "événement" s'appelle un " message " ou "signal", et même avoir un "message" mot-clé et syntaxe de sucre spécifique.

const
  WM_Paint = 998;  // <-- "question" can be done by several talkers
  WM_Clear = 546;

type
  MyWindowClass = class(Window)
    procedure NotEventHandlerMethod_1;
    procedure NotEventHandlerMethod_17;

    procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener
    procedure DoClearEventHandler; message WM_Clear;
  end;

Et, pour répondre à ce "message", un "gestionnaire d’événements" " répondre, qu’il s’agisse d’un seul délégué ou de plusieurs délégués.

Résumé: " événement " est la "question", "gestionnaire (s) d'événements" sont la réponse.

Voici ma solution:

public class Foo : IDisposable
{
    private event EventHandler _statusChanged;
    public event EventHandler StatusChanged
    {
        add
        {
            _statusChanged += value;
        }
        remove
        {
            _statusChanged -= value;
        }
    }

    public void Dispose()
    {
        _statusChanged = null;
    }
}

Vous devez appeler Dispose () ou utiliser à l'aide du modèle (new Foo ()) {/*...*/} pour désabonner tous les membres de la liste d'appels. .

Supprimez tous les événements, en supposant qu'il s'agisse d'une "Action". type:

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top