Подписка на событие на время использования блока


Я часто сталкиваюсь со следующим кодом:

myService.SomeEvent += listener;
myService.DoSomething();
myService.SomeEvent -= listener;
Это здорово, но было бы здорово, если бы мы могли сделать это более приятным способом. Я думал сделать что-то вроде:
using(EventScope.Start(myService.SomeEvent, listener)){
    myService.DoSomething();
}

К сожалению, это запрещено C#, потому что myService.Некоторые события могут появляться только с левой стороны от a += или a -= (по уважительной причине). Мой вопрос в том, какие еще варианты у меня есть? В идеале я хотел бы, чтобы это было типобезопасно, что исключает рефлексию и выполнение следующего (что я уже сделал реализовано):

using(EventScope.Start(myService, "SomeEvent", listener){
    myService.DoSomething();
}
Чтобы быть ясным, я не женат на использовании синтаксиса "using", и, возможно, вы могли бы сказать, что это извращение языка. Другие варианты были бы оценены!
2   2  

2 ответа:

Вероятно, есть способ сделать это с более чистым синтаксисом, но если у вас есть такая структура...

public struct ActionDisposable : IDisposable
{
    private readonly Action _action;

    public ActionDisposable(Action action)
    {
        _action = action;
    }

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

...и метод, подобный этому:

public static IDisposable EventScope(Action subscribe, Action unsubscribe)
{
    subscribe();
    return new ActionDisposable(unsubscribe);
}

Это позволит вам написать такой код:

using (EventScope(() => myService.SomeEvent += listener, () => myService.SomeEvent -= listener))
{
    myService.DoStuff();
}

Или вот так:

myService.SomeEvent += listener
using (new ActionDisposable(() => myService.SomeEvent -= listener))
{
    myService.DoStuff();
}

Вы беспокоитесь, что событие не будет отменено из-за исключения или чего-то еще? Если это так, вы можете использовать try / finally. В противном случае, я думаю, что оригинальный способ лучше, и выглядит просто прекрасно для меня.