using (start/end)


I'm trying to build something similar to the TimedLock class, but for start & end events.  I want to be able to use it like this:



                  using (this.StartEndEvent.Open(this))


                  {


                        // ... do something


                  }


Which would mean:



                  this.StartEndEvent.OnStart(this);


                  // ... do something


                  this.StartEndEvent.OnEnd(this);


(add try/finally as needed).


Here’s my first cut.  Can we make it better?



      class StartEndEvent : IDisposable


      {


            public event EventHandler OnStart;


            public event EventHandler OnEnd;


 


            object _sender;


 


            public IDisposable Open(object sender)


            {


                  this._sender = sender;


                  this.OnStart(_sender, null);


                  return (IDisposable)this;


            }


 


            void IDisposable.Dispose() { this.OnEnd(_sender, null); }


 


      }


 

Comments (9)
  1. Jerry Pisk says:

    I would go with a method returning StartEndEvent object and put the Open code into its ctor. That way the usage would be a little more intuitive and safe (in your version you can have multiple using blocks using the same object, since you’re not creating a new one but sharing an existing.

  2. Bjarne Stroustrup did an article on something similar in C++. I can’t find it, but this is looks to be close http://www.research.att.com/~bs/wrapper.pdf

    This is the kind of behavior I miss most from C++. It is very powerful.

  3. Why not go all the way?

    public class EventSpanner : IDisposable

    {

    private readonly EventHandler _end;

    private readonly object _sender;

    public EventSpanner(object sender, EventHandler start, EventHandler end)

    {

    _sender = sender;

    start(sender, EventArgs.Empty);

    _end = end;

    }

    void IDisposable.Dispose()

    {

    _end(_sender, EventArgs.Empty);

    }

    }

    Then, you could go:

    public class Machinery

    {

    public event StartMachinery;

    public event StopMachinery;

    public void Run()

    {

    using(new EventSpanner(this, StartMachinery, StopMachinery))

    {

    // "machinate"

    }

    }

    }

  4. jaybaz [MS] says:

    I have to apologize. This post was written up in great haste, and the code still has plenty of room for improvement.

    Dmitry:

    I was thinking that the Start and Stop events should be owned by the EventSpanner. Having the Machinery class expose the EventSpanner seems beneficial. Then the consumer sees the semantic relationship of the events being supported by the class structure.

    Consider if there was a 3rd, unrelated event. Seeing:

    – OnStart

    – OnEnd

    – OnFire

    I see that OnStart and OnEnd are a pair, and belong together; that they are somehow more like each other than like OnFire.

    – SpannedEvent.OnStart

    – SpannedEvent.OnEnd

    – OnFire

    What do you think?

  5. No need to apologize. This is a blog, not an online magazine. We expect you to be imperfect 🙂

    Here’s my reasoning on this. By making EventSpanner generic, you make it a pattern. Now, not only Machinery, but also KnotTyingCompetition can enjoy the benefit of the same EventSpanner.

    If the sequence of events fired is controlled from the inside of the class that hosts the events, there is no reason to have EventSpanner as member of the hosting class and thus, no reason for Start and End events to be owned by EventSpanner.

    What do you think back at ya.

  6. jaybaz [MS] says:

    Maybe we can decompose the problem further. I see several notions:

    1. Do something before and after something else.

    2. Fire a given event before and after something else.

    3. Manage OnStart and OnEnd events.

    So I think I would make 3 classes, each based on the previous.

    This hits both what you were doing & what I was doing.

  7. Sounds good.

    Do you think a controller-type situation would work well?

    EvenSpannerBase(IEventSpanEnabled subject)

    {

    _subject = subject;

    _subject.Start();

    }

    void IDisposable.Dispose()

    {

    _subject.End();

    }

Comments are closed.

Skip to main content