Getting a return value from a Task with C#
January 17, 2014 15 Comments
Sometimes you want to get a return value from a Task as opposed to letting it run in the background and forgetting about it. You’ll need to specify the return type as a type parameter to the Task object: a Task of T.
.NET 4.0
Without specifying an input parameter:
Task<int> task = new Task<int>(() => { int total = 0; for (int i = 0; i < 500; i++) { total += i; } return total; }); task.Start(); int result = Convert.ToInt32(task.Result);
We count to 500 and return the sum. The return value of the Task can be retrieved using the Result property which can be converted to the desired type.
You can provide an input parameter as well:
Task<int> task = new Task<int>(obj => { int total = 0; int max = (int)obj; for (int i = 0; i < max; i++) { total += i; } return total; }, 300); task.Start(); int result = Convert.ToInt32(task.Result);
We specify that we want to count to 300.
.NET 4.5
The recommended way in .NET 4.5 is to use Task.FromResult, Task.Run or Task.Factory.StartNew:
FromResult:
public async Task DoWork() { int res = await Task.FromResult<int>(GetSum(4, 5)); } private int GetSum(int a, int b) { return a + b; }
Please check out Stefan’s comments on the usage of FromResult in the comments section below the post.
Task.Run:
public async Task DoWork() { Func<int> function = new Func<int>(() => GetSum(4, 5)); int res = await Task.Run<int>(function); } private int GetSum(int a, int b) { return a + b; }
Task.Factory.StartNew:
public async Task DoWork() { Func<int> function = new Func<int>(() => GetSum(4, 5)); int res = await Task.Factory.StartNew<int>(function); } private int GetSum(int a, int b) { return a + b; }
View the list of posts on the Task Parallel Library here.
Hi Andras,
I have one question – which way is the best?
Hi Dmitry,
it is recommended to avoid the Task constructor, i.e. Task t = new Task; t.Start;. If you can run your project on .NET4.5 then you can take the FromResult approach, otherwise any of the static approaches are fine: Task.Factory.Start, Task.Run, Task.FromResult
//Andras
On a tangent, are tasks the “preferred” way of multithreading in C#?
Definitely.
You can also learn about the await-async keywords that are used in conjunction with Tasks to co-ordinate threads.
//Andras
Thanks for the advice. I’ll try to make use of them in the future. I am relatively new to .NET and C#, coming from C++, and I have to admit that I envy the language features sometimes. 😛
Hi Andras,
nice article! But there is one flaw.
Task.FromResult() is NOT async! It’s just a wrapper to get a Task with Status “RanToCompletion”.
Your calling Thread will block until your operation is completed.
Another way to get a (running) Task is the TaskCompletionSource (see: http://msdn.microsoft.com/de-de/library/dd449174%28v=vs.110%29.aspx)
With a TaskCompletionSource you have more control over the tasks state Exception,Finished,Cancelled.
Hi Stefan,
Thanks for your comment. What’s the point of having Task.FromResult then? Can you give a simple code example how it can be used?
Thanks,
Andras
Hi Andras,
ASP.Net Web Api for example.
(Source: https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/MessageHandlers/RequireHttpsHandler.cs
I replaced TaskCompletionSource with Task.FromResult() because it’s not available in .Net4)
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
if (request.RequestUri.Scheme == Uri.UriSchemeHttps) {
return base.SendAsync(request, cancellationToken);
}
var response = CreateResponse(request);
return Task.FromResult(response);
}
I used the first method, it works, but my UI still freezes. Am I missing something?
Do you mean that the UI freezes for the duration of executing the task? When working with tasks in a UI application you have to make your asynchronous methods awaitable with the await and async keywords. Do you know what I mean? //Andras
Pingback: How To Get A Return Value From A Thread C# | Technology Loves
getting System.Threading.THreadiing.GetResultCore() @ task.Result line;
You can use ValueTask
Good.
Maybe you want to read something on this topic. https://stackoverflow.com/questions/21033150/any-difference-between-await-task-run-return-and-return-task-run , http://www.tugberkugurlu.com/archive/should-i-await-on-task-fromresult-method-calls and https://stackoverflow.com/questions/46439237/what-is-a-proper-situation-for-await-task-startnew