2

I currently have code like this, an an async method:

MyEventHandler handler = (sender, e) => ...

Foo.My += handler;

await Foo.Bar();  // Fires event `My` 

Foo.My -= handler;

I want to use a using statement to handle the before-and-after nature of this code. Perhaps somethign like:

using (ListenUntilDispose(Foo.My, handler))
{
    await Foo.Bar();
}

But I can't figure out to write ListenTemporarily.

Is there a way to do this?

Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
  • 7
    Add a class that implements IDisposable. Set Foo.My += handler; in constructor. remove it in Dispose method. – Marvin Smit Oct 28 '13 at 20:34
  • I wish MS had either had event subscription return an `IDisposable`, and/or specified that event delegates must include a means of asking a subscriber whether it was still interested, and subscribers must be prepared to be asked that at any time (publishers could ask subscribers when an event is invoked, and also periodically when new subscribers are added without invoking an event). – supercat Oct 28 '13 at 21:14

1 Answers1

1

Yes, there is, but unfortunately it's not straightforward to do this generically, because events are not reified in C# - what I mean is, you can't pass around a reference to an event.

In the Reactive Extensions, this is worked around by using reflection, so you pass an event to a function by passing the object it is defined on, and the name of the event as a string:

using(ListenUntilDispose(Foo, "My", handler))
{
    await Foo.Bar();
}

However, my reflection-fu is not terribly strong, and you also lose static type safety, meaning that the compiler can't check if handler really matches up with Foo.My. Here's another suggestion that is not as comfortable but might also suit you, if your goal really is "I want to use using" and not necessarily "I want the most easily readable solution":

class DelegateDisposable : IDisposable
{
    private readonly Action m_dispose;
    public DelegateDisposable(Action onDispose)
    {
        m_dispose = onDispose;
    }

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

Usage would be:

Foo.My += handler;
using(new DelegateDisposable(() => Foo.My -= handler))
{
    await Foo.Bar();
}

Disclaimer: Written in the edit box, so untested :)

Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
Medo42
  • 3,821
  • 1
  • 21
  • 37
  • You might also want to read the excellent answer about how to properly implement the IDisposable interface: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface?answertab=active#tab-top :) –  Oct 28 '13 at 21:27
  • 2
    How does this apply here? I don't have any unmanaged resources to dispose of, so we don't need / can't use a finalizer. So there's also no need for a bool parameter to `Dispose` (we're always disposing the managed resources) or for `SuppressFinalize` (nothing to suppress because we don't have one). Which leaves... the plain `Dispose` method. Why make things more complicated than they need to be? – Medo42 Oct 28 '13 at 22:37
  • You are right. In this context, it would make matters more complicated. Perhaps i got carried away a bit :S –  Oct 28 '13 at 22:50