locked
binding event fire to Task completion

    Question

  • Congratulations to authors!

    Async CTP is really cool.

     

    I have a question probably similar to http://social.msdn.microsoft.com/Forums/en-US/async/thread/ed8a14e8-d19a-42d1-bc3f-7017bdfed09c.

    Is it possible to create Task from event fired?

     

    Some example:

    Method Stop() initiates stopping of engine. The only stop notification is event Stopped.

     

    public class Engine
    
    {
    
    ...
    
    public event Action Stopped;
    
    public void Stop()
    
    {
    
    ...
    
    }
    }
    
    

     

    Is it possible to create method Stop returning Task

     

    public class Engine
    
    {
    
    ...
    
    public event Action Stopped;
    
    public Task Stop()
    
    {
    
    ...
    
    }
    }
    

     

     

    and later use it with await keyword?

     

    async int f()
    
    {
    
    var engine = new Engine();
    
    await engine.Stop();
    
    // some code after stop
    }
    
    Sergey.
    Sergey.
    Friday, October 29, 2010 2:25 PM

Answers

  • Sergey,


    You'd have to either wrap this class, or alter it, so that Stop() returned a Task.  Unfortunately, wrapping an EAP pattern into a Task is a bit more complicated than the APM pattern, where it's handled automatically.

    If you don't want to support cancellation or anything like that, you should be able to do:

    private Task<bool> StopEngine(Engine engine)
    {
      TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    
      // Mark the task completed when the engine stops
      engine.Stopped += () =>
        {
          tcs.SetResult(true);
        };
    
      engine.Stop();
      return tcs.Task;
    }
    

    With this method, you could then do:

    async int f()
    {
      var engine = new Engine();
    
      // Do stuff with engine...
    
      var stopped = await StopEngine();
    
      // some code after stop
    }
    

     

    <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="white-space:normal"><br/></span></span>
    
    <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="white-space:normal"><br/></span></span>
    


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Friday, October 29, 2010 7:43 PM

All replies

  • Sergey,


    You'd have to either wrap this class, or alter it, so that Stop() returned a Task.  Unfortunately, wrapping an EAP pattern into a Task is a bit more complicated than the APM pattern, where it's handled automatically.

    If you don't want to support cancellation or anything like that, you should be able to do:

    private Task<bool> StopEngine(Engine engine)
    {
      TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    
      // Mark the task completed when the engine stops
      engine.Stopped += () =>
        {
          tcs.SetResult(true);
        };
    
      engine.Stop();
      return tcs.Task;
    }
    

    With this method, you could then do:

    async int f()
    {
      var engine = new Engine();
    
      // Do stuff with engine...
    
      var stopped = await StopEngine();
    
      // some code after stop
    }
    

     

    <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="white-space:normal"><br/></span></span>
    
    <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="white-space:normal"><br/></span></span>
    


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Friday, October 29, 2010 7:43 PM
  • Sergey,


    You'd have to either wrap this class, or alter it, so that Stop() returned a Task.  Unfortunately, wrapping an EAP pattern into a Task is a bit more complicated than the APM pattern, where it's handled automatically.

    If you don't want to support cancellation or anything like that, you should be able to do:

     

    private Task<bool> StopEngine(Engine engine)
    {
     TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    
     // Mark the task completed when the engine stops
     engine.Stopped += () =>
      {
       tcs.SetResult(true);
      };
    
     engine.Stop();
     return tcs.Task;
    }
    

     

    With this method, you could then do:

     

    async int f()
    {
     var engine = new Engine();
    
     // Do stuff with engine...
    
     var stopped = await StopEngine();
    
     // some code after stop
    }
    

     

     

     

    <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="white-space:normal"><br/></span></span>
    
    <span style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="white-space:normal"><br/></span></span>
    

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Reed,

     

    thank you!

    By the way is it possible to deal with TaskCompletionSource for Tasks with no result value?

    In my example I don't need any result value.

     

    Sergey.


    Sergey.
    Saturday, October 30, 2010 6:14 AM
  • You can - you just have to treat it as object, and allow it to be used cast back to a Task from Task<object>.  Since Task<T> subclasses Task, it works fine.

     

    Doing this, you could write the above as:

    private Task StopEngine(Engine engine)
    {
     TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    
     // Mark the task completed when the engine stops
     engine.Stopped += () =>
      {
       tcs.SetResult(null);
      };
    
     engine.Stop();
     return tcs.Task;
    }
    
    

     

    There is, unfortunately,  no non-generic TaskCompletionSource.  I've actually provided feedback on this recently - feel free to share your thoughts there on the subject, if you have any.

     

    -Reed

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Saturday, October 30, 2010 3:05 PM