2017-11-24 5 views
0

Hier ist ein Szenario:Ist es möglich, mehrere Ereignisse mit einem einzigen Methodenaufruf abzubestellen?

ich eine Klasse, die für viele verschiedene Veranstaltungen abonniert:

ProviderOfFruit.Event += OnFruitHarvested; 
ProviderOfCars.Event += OnCarBrokeDown; 
ProviderOfPeople.Event += OnPersonAwoke; 
...etc 

Später will ich von all diesen zugleich abzumelden. Bin ich verurteilen dies in vollem Umfang aus dem Schreiben:

ProviderOfFruit.Event -= OnFruitHarvested; 
ProviderOfCars.Event -= OnCarBrokeDown; 
ProviderOfPeople.Event -= OnPersonAwoke; 
...etc 

Oder ist es eine Möglichkeit, etwas entlang der Linien von dem zu tun:

ListOfEvents.Unsubscibe(); ? 

HINWEIS: Ich möchte nicht ein Ereignis von allen löschen seine Abonnenten, viele Klassen, die ich zu einer Veranstaltung abonniert habe. Ich möchte nur, dass eine dieser Klassen die abonnierten Ereignisse abbestellt. Das Ziel ist, dass ich nie vergesse, mich von einer bestimmten Veranstaltung abzumelden.

+0

kann hilfreich sein https://StackOverflow.com/Questions/153573/How-Can-Clear-Event-subscriptions-in-C – melya

+0

im schlimmsten Fall könnten Sie sie in einer Liste zu halten, dann durchlaufen Sie sie zum Abbestellen Jeder, denke ich. – ADyson

+0

@melya Es geht darum, alle Abonnenten von 1 Ereignis zu entfernen, ich möchte alle Abonnements, die ich gemacht habe, von einer beliebigen Anzahl verschiedener Ereignisse entfernen. –

Antwort

-1

Sie können das folgende Muster verwenden. Erste Klasse erstellen, die beliebige Funktion ausgeführt wird passieren Sie auf dem Bau und dem anderen auf dispose:

public class EventSubscription : IDisposable { 
    private readonly Action _unsubscribe; 

    private EventSubscription(Action subscribe, Action unsubscribe) { 
     _unsubscribe = unsubscribe; 
     subscribe(); 
    } 

    public static IDisposable Create(Action subscribe, Action unsubscribe) { 
     return new EventSubscription(subscribe, unsubscribe); 
    } 

    public void Dispose() { 
     _unsubscribe(); 
    } 
} 

Dann Feld in Ihrer Klasse erstellen, wo Sie abonnieren Sie Ereignisse:

private static readonly List<IDisposable> _subscriptions = new List<IDisposable>(); 

und abonnieren wie folgt aus:

_subscriptions.Add(EventSubscription.Create(
    () => Event1 += OnEvent1, 
    () => Event1 -= OnEvent1)); 
_subscriptions.Add(EventSubscription.Create(
    () => Event2 += OnEvent2, 
    () => Event2 -= OnEvent2)); 

Wenn Sie wieder abbestellen müssen, tun gerade:

_subscriptions.ForEach(c => c.Dispose()); 

Vorteile sind das Abmelden von allen auf einmal, und viel weniger Chance zu vergessen, abzubestellen, weil Sie immer += und -= Handler in Paar, im selben Anruf übergeben.

Variation dieser ist dieser allgemeine Zweck Klasse:

public class Disposable : IDisposable { 
    private readonly Action _action; 
    private Disposable(Action action) { 
     _action = action; 
    } 
    public static IDisposable FromAction(Action action) { 
     return new Disposable(action); 
    } 
    public void Dispose() { 
     _action(); 
    } 
} 

Sie können es bereits an vielen Orten finden (wie .NET reaktive Erweiterungen), aber wenn nicht - Sie selbst umsetzen können. Dann obige Code wird:

Event1 += OnEvent1; 
_subscriptions.Add(Disposable.FromAction(() => Event1 -= OnEvent1)); 

Mit IDisposable natürlich nicht notwendig ist, können Sie nur Liste von Aktionen haben.

+0

Dies ist definitiv ein Schritt in die richtige Richtung, aber immer noch viel redundanten Code und das Potenzial für Fehler, können wir es besser machen? (Das erste, was ich sehen kann, ist eine benutzerdefinierte Sammlung unter Subscribe und Abmelden Lamdas, gibt es andere Verbesserungen?) –

+0

@MarkBamford Ich glaube nicht, so leider (abgesehen von kleinen Verbesserungen, die nicht die allgemeine Idee ändern). Sie können reflection verwenden, um subscribe \ unsubscribe zu abonnieren, aber dann müssen Sie das Ereignisziel (Objekt mit Zielereignis) und den Ereignisnamen als Zeichenfolge übergeben, wodurch sich noch mehr Fehlermöglichkeiten ergeben. Das Problem besteht darin, dass Sie das Ereignis nicht als Argument an eine andere Funktion übergeben können (so dass die Funktion es unterbenutzen kann) oder speichern Sie es in Array \ field. – Evk

0

Ja, Sie können alle Ereignisse, die eine Klasse abonniert, in einer Sammlung behalten und über sie hinwegschleifen. Dadurch müssen Sie nicht jedes Ereignis während des Abonnements und dann noch einmal beim Abmelden auflisten - und als Bonus hilft es, die Möglichkeit zu verhindern, ein Ereignis an einem Ort zu verpassen.

Dies ist jedoch begrenzt und löst nicht das größte Problem Ihrer Klasse mit einer harten Abhängigkeit von so vielen anderen Klassen. Ihr Beispiel liefert nicht genügend Details, um es mit Sicherheit zu sagen, aber Sie können das Event Aggregator Nutzungsmuster finden.

+0

"Sie können alle Ereignisse in einer Klasse halten Abonniert in einer Sammlung und Schleife über sie. " Können Sie ein Beispiel dafür geben? –

+0

Diese Antwort von einer anderen SO-Frage beschreibt eine Methode dazu (aber sehen Sie sich den Aggregator an und ermitteln Sie, ob er Ihren Anforderungen entspricht) - https://stackoverflow.com/a/16135376/413399 –

+0

Das Ereignis-Aggregator-Muster tut dies nicht sehen aus, als was ich brauche, und das Beispiel der Sammlung scheint auch nicht richtig zu sein. Ich habe den Hauptbeitrag bearbeitet, um hoffentlich klarzustellen, worauf ich hinarbeite. Ich habe keinen konkreten Fall, den ich zu lösen versuche, es ist eher etwas, was ich häufig mache und es fühlt sich an, als wäre ich etwas TROCKENER. –

Verwandte Themen