Event

De Banane Atomic
Révision datée du 4 octobre 2018 à 14:50 par Nicolas (discussion | contributions) (→‎Event vs Delegate)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigationAller à la recherche

Utilisation

Program est abonné à l'évènement MonEvent.
Lorsque MaClasse lance l'évènement MonEvent, la méthode maClasse_MonEvent de Program sera exécutée.

Cs.svg
class Program
{
    static void Main(string[] args)
    {
        var maClasse = new MaClasse();
        maClasse.MonEvent += new EventHandler<MonEventArgs>(maClasse_MonEvent);
        // délégué anonyme (_sender, _e) = (object sender, MonEventArgs e)
        maClasse.MonEvent += (_sender, _e) => { Console.WriteLine(_e.Message); };
        maClasse.LancerEvenement();
    }

    static void maClasse_MonEvent(object sender, MonEventArgs e)
    {
        Console.WriteLine(e.Message);
    }
}

public class MaClasse
{
    public event EventHandler<MonEventArgs> MonEvent;

    // permet au code extérieur à la classe de lancer l’événement.
    public void LancerEvenement()
    {
        OnMonEvent("message");
    }

    // déclarer cette méthode protected pour que les classes dérivées puissent lancer l’événement
    // et virtual pour que les classes dérivées puissent modifier le lancement de l’événement.
    protected virtual void OnMonEvent(string message)
    {
        // Nouvelle méthode avec l'opérateur conditionnel null
        MonEvent?.Invoke(this, new MonEventArgs() { Message = message });

        // Ancienne méthode
        // Make a temporary copy of the event to avoid possibility of a race
        // condition. If the last subscriber unsubscribes immediately after the
        // null check and before the event is raised.
        var handler = MonEvent;
        if (handler != null)
        {
            handler(this, new MonEventArgs() { Message = message });
        }
    }
}

public class MonEventArgs : EventArgs
{
    public string Message { get; set; }
}

Héritage

Un événement n'est accessible que depuis sa classe, quelque soit son modificateur d'accès, car l'EventHandler est toujours déclaré private.

Cs.svg
public event EventHandler MonEvent;
// la déclaration précédente correspond en fait à
private EventHandler monEventDelegate;
public event EventHandler MonEvent
{
    add { monEventDelegate += value; }
    remove { monEventDelegate -= value; }
}

MonEvent(this, EventArgs.Empty);
// l'appel précédent correspond en fait à
monEventDelegate(this, EventArgs.Empty);

Solution de contournement : utiliser une méthode protected qui encapsule le lancement de l’événement.

Supprimer tous les EventHandlers associés à un event

pour ce faire il faut intercepter l'ajout d'EventHandlers et les stocker en vue de la suppression.

Cs.svg
private ArrayList _eventHandlersList = new ArrayList();

private EventHandler _monEventHandler;
public event EventHandler MonEvent
{
    add
    {
        _monEventHandler += value;
        // on intercepte l'ajout d'EventHandler et on en profite pour l'enregistrer dans _eventHandlersList
        _eventHandlersList.Add(value);
    }
    remove
    {
        _monEventHandler -= value;
        _eventHandlersList.Remove(value);
    }
}

public void RemoveAllEventHandlers()
{
    foreach (EventHandler eventHandler in _eventHandlersList)
    {
        _monEventHandler -= eventHandler;
    }
    delegates.Clear();
}

public void Méthode()
{
    MonEvent += new EventHandler(...);
    MonEvent += new EventHandler(...);

    // on supprime tous les EventHandler associés à MonEvent
    RemoveAllEventHandlers();
}

Event vs Delegate

L'Event est un wrapper autour de Delegate.
Event ne permet pas d'assignation direct d'un delegate, mais plutôt l'ajout de delegate.

Cs.svg
var maClasse = new MaClasse();
// il n'est pas possible d'assigner directement un delegate à un event
maClasse.MonEvent = null;
// on peut juste ajouter un delegate à l'event
maClasse.MonEvent += (_sender, _e) => { /* ... */ };