Reputation: 12599
When using an anonymous method in a LINQ Select
statement does the anonymous method have to return a value?
When I do the following I get no errors:
await Task.WhenAll(list.Select(a => doSomething(a)));
But when I do this I get an error that says type arguments cannot be inferred from the usage
:
await Task.WhenAll(list.Select(a => {
doSomething(a);
Log("Log Something");
UpdateUI();
}));
Why does the first work and the second doesn't?
Here is the doSomething
method:
private async Task doSomething(string a)
{
HttpClient client = new HttpClient;
// Do stuff
string source = await client.PostAsync(a, content);
// Extract data from source and store in text file.
}
Upvotes: 1
Views: 2620
Reputation: 203842
When using an anonymous method in a LINQ Select statement does the anonymous method have to return a value?
Yes. The signature of the Select
method is:
public IEnumerable<TResult> Select<TSource, TResult>(
IEnumerable<TSource> source,
Func<TSource, TResult> selector)
so the selector must return a value.
With your first code snippet the return statement is implicit. doSomething
returns a value, and that value is what each item is projected to.
When you use a statement lambda, instead of an expression lambda, there is no implicit return statement. Since your second code block is not returning anything, it doesn't match what Select
expects.
Now, as for your actual problem. What you want to do is project each task into a task that does something, then writes to the log when it's done and updates the UI. You can use an async
lambda to do this. In an async
lambda when there are no return
statement it will still be returning a Task
(just without a Result
) instead of void
. And that's exactly what you want to do, project each task into another task.
await Task.WhenAll(list.Select(async a => {
await doSomething(a);
Log("Log Something");
UpdateUI();
}));
Upvotes: 5
Reputation: 101690
Yes, the function you pass to Select()
has to return a value, because the purpose of Select
is to change one set of values into another set of values. How about this:
Define this method:
private async Task DoSomethingLogAndUpdate(string a)
{
await doSomething(a);
Log("Log Something");
UpdateUI();
}
Then do:
await Task.WhenAll(list.Select(a => DoSomethingLogAndUpdate(a)));
Or to do this without defining a separate method:
await Task.WhenAll(list.Select(async a => {
await doSomething(a);
Log("Log Something");
UpdateUI();
}));
Upvotes: 2
Reputation: 9005
The first one is a simple expression, so the type of that expression is used as the return type of the lambda.
From MSDN:
A lambda expression with an expression on the right side of the => operator is called an expression lambda. Expression lambdas are used extensively in the construction of Expression Trees (C# and Visual Basic). An expression lambda returns the result of the expression
(Emphasis mine)
However, what you have is a statement lambda, which means that in order to return a value, you must have a return
statement in the lambda body.
Upvotes: 2