简体   繁体   中英

Is it possible to unsubscribe from multiple events with a single method call?

Here is a scenario:

I have a class which subscribes to many different events:

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

Later I want to unsubscribe from all of these at the same time. Am I doomed to writing this out in full:

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

Or is there a way to do something along the lines of:

ListOfEvents.Unsubscibe(); ?

NOTE: I do not want to clear an event of all its subscribers, many classes my be subscribed to an event. I just want one of those classes to unsubscribe from the events it is subscribing to. The aim here being that I never forget to unsubscribe from a particular event.

Yes, you can keep all the events a class subscribes to in a collection and loop over them. This keeps you from having to list each event during subscription and then again when unsubscribing -- and, as a bonus, helps to prevent the possibility of missing an event in one place or another.

However, this is limited and doesn't solve the biggest problem of your class having a hard dependency on so many other classes. Your example doesn't provide enough detail to say for certain, but you may find the Event Aggregator pattern of use.

You can use the following pattern. First create class which will run arbitrary function you pass on construction and another on 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();
    }
}

Then create field in your class where you subscribe to events:

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

And subscribe like this:

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

When you need to unsubsribe, just do:

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

Advantages include unsubscribing from all at once, and much less chance to forget to unsubscribe, because you always pass += and -= handler in pair, in the same call.

Variation of this is this general purpose class:

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();
    }
}

You can find it already in many places (like .NET reactive extensions), but if not - you can implement yourself. Then above code becomes:

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

Using IDisposable is not necessary of course, you can just have list of Actions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM