Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use the Task.Run(Func<Task> f) method signature?

Tags:

c#

To use this method :

public static Task Run(Action action)

I just write :

void MyMethod(){ //do something }
Task t = Task.Run(new Action(MyMethod));

However I do not understand how to use the following overload

public static Task Run(Func<Task> f)

The msdn mentions that the returned task is "a proxy for the task returned by f" which is even more confusing to me. What is meant by proxy and how would I call this method?

like image 308
sam95 Avatar asked May 22 '15 15:05

sam95


People also ask

What is Task run ()?

The Run method allows you to create and execute a task in a single method call and is a simpler alternative to the StartNew method. It creates a task with the following default values: Its cancellation token is CancellationToken.

How do I start a new Task in C#?

To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();

What is Task and Task t?

Task<T> also represents an operation which might be in progress, or might have been cancelled, faulted, or might have completed. However, a completed Task<T> will contain the result of that operation, which you can then read.

What is TResult in C#?

TResult. The type of the return value of the method that this delegate encapsulates. This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived. For more information about covariance and contravariance, see Covariance and Contravariance in Generics.


3 Answers

Func<Task> is simply a function that returns a task. That task is then executed.

So Task Run( Func<Task> f ) returns a Task, whose job is to run another Task (the one created by f). That's what's meant by a "proxy".

However, read the Note on MSDN (emphasis added):

The Run<TResult>(Func<Task<TResult>>) method is used by language compilers to support the async and await keywords. It is not intended to be called directly from user code.

like image 186
D Stanley Avatar answered Oct 16 '22 01:10

D Stanley


Func<T> is a generic delegate - here's its full signature:

public delegate TResult Func<out TResult>()

As you can see, it represents a function that takes no parameters, and returns an instance of type TResult. In the case of Func<Task>, TResult is Task.

What this means, is that you can do this:

public Task MyAsyncMethod() { ... }

Task.Run(MyAsyncMethod); 

This converts your method MyAsyncMethod into a delegate of type Func<Task> and passes it to Task.Run. It's syntactic sugar for Task.Run( new Func<Task>(MyAsyncMethod) );

The msdn mentions that the returned task is "a proxy for the task returned by f" which is even more confusing to me (what is meant by proxy ?)

What this means is that Task.Run will simply wrap the task returned by MyAsyncMethod is another Task.

like image 37
dcastro Avatar answered Oct 15 '22 23:10

dcastro


That signature allows you to provide a method that returns a Task, when you run Task.Run. That is because the last generic argument of a Func<T> is the return value given back by the delegate you provide. Meaning:

public Func<bool> IsValid = this.ValidateUser;
public bool ValidateUser() { return someUser.IsAuthenticated; }

or even just

public Func<bool> IsValidUser = this.User.IsAuthenticated;

Then you can use the delegate as you would any other method, and the delegate will return a bool.

public void Foo()
{
    if (!IsValidUser()) throw new InvalidOperationException("Invalid user");
}

You can use parameters that are passed in to the delegate, by providing additional generic types other than the return value.

Func<int, bool> IsUserAgeValid = (age) => return age > 18;

// Invoke the age check
bool result = this.IsUserAgeValid(17);

The thing to remember is that the last generic is always the return type in a Func. If only one generic is provided, then there is no parameters, only a return type.

A Func<Task> allows you to use an awaitable method in your Task.Run call. This also means that you can await from within the anonymous delegate you provide.

public Task Foo()
{
    /* .. do stuff */
}

public void Bar()
{
    Task.Run(async () => 
        {
            await Foo();
            /* do additional work */
        });
}

and if you don't need to await the call to Foo(), you can just give Task.Run the Foo method.

Task.Run(Foo);

If you find yourself wanting to await the awaitable method given to Task.Run as shown above, it is probably better that you use ContinueWith.

public void Bar()
{
    Task.Run(Foo).ContinueWith(foosTaskResult => 
    {    
        /* Do stuff */
    });
}

The MSDN documentation saying the the Task returned is a proxy for the Task of f, basically means that

Task returnedTask = Task.Run(Foo);

will set returnedTask to be the Task that was returned by the call to the awaitable Foo() method.

like image 31
Johnathon Sullinger Avatar answered Oct 16 '22 00:10

Johnathon Sullinger