locked
Async Task with No 'await' RRS feed

  • Question

  • I have the following scenario:

     

    abstract class A
    {
    	public abstract Task Foo();
    }
    
    class B : A
    {
    	public override async Task Foo()
    	{
    		DoSomething1();
    		await DoSomething2Async();
    		DoSomething3();
    	}
    }
    
    class C : A
    {
    	public override async Task Foo()
    	{
    
    		DoSomething4();
    	}
    }
    

    There is an abstract class that defines some abstract method and some of the child classes need to perform asyncrhonous operations while others do not. The problem is that the compiler generates a warning since no "await" is used in C.Foo. Can you please remove that warning since there seem to be valid cases for it? Or is there a better way to handle it?

    I really hope that the indended solution is not this:

    class C : A
    {
    	public override async Task Foo()
    	{
    
    		return new Task(() =>
    			{
    				DoSomething4();
    			});
    	}
    }
    

    This would be way too messy. Perhaps it is possible to perform the task inside the method and return a null task. Is that a good idea?

    Here's an aproach:

    Remove the async keyword. Let methods that return Task or Task<T> be special (just like methods that return IEnumerable<T>). Make it so that the await keyword can be used in those special task methods.

    This is exactly the same paradigm that iterators use. For example, we don't have this:

    public iterator IEnumerable<int> Foo()
    {
       ...
       yield return ...;
       ...
    }

    so why should we have this?:

    public async Task<int> Foo()
    {
       ...
       await ...;
       ...
    }

    Let's just do this:

    public Task<int> Foo()
    {
       ...
       await ...;
       ...
    }

    Also, have the ability to do async on methods that return void is not needed. People can just use Task.Factory.StartNew(...) or some other simple method can be created.

    -Emil

    Sunday, October 31, 2010 6:44 PM

Answers


  • class
    C : A { public override async Task Foo() { DoSomething4(); } }

    There is an abstract class that defines some abstract method and some of the child classes need to perform asyncrhonous operations while others do not. The problem is that the compiler generates a warning since no "await" is used in C.Foo. Can you please remove that warning since there seem to be valid cases for it? Or is there a better way to handle it?

     

    You can handle this by returning a completed task directly after running your method synchronously (and just leave out the async keyword, since it's not awaiting anything):

     

      class C : A
      {
        public override Task Foo()
        {
          DoSomething4();
    
          TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
          tcs.SetResult(null);
          return tcs.Task;
        }
      }
    

    However, I'd take special care to make sure that "DoSomething4" was very "quick" - otherwise, this method may violate the Liskov Substitution Principle.  In your case, a caller of this API would expect Foo() to be a very short lived, asynchronous operation - turning it synchronous in only some subclasses would violate expectations.

     

    BTW - the TPL team is taking feedback on making this simpler.  If you feel this is important, I'd chime in there...

     

     

     

     

    Also, have the ability to do async on methods that return void is not needed. People can just use Task.Factory.StartNew(...) or some other simple method can be created.

    -Emil

    I don't like this idea at all...

    This would make it impossible to use async/await on UI event handlers.  They are almost always "void" methods.  This adds a huge amount of usability.

     

    -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".
    Sunday, October 31, 2010 7:57 PM
    Moderator