简体   繁体   English

LINQ选择语句。 匿名方法返回异常

[英]LINQ Select Statement. Anonymous Method Returns Exception

When using an anonymous method in a LINQ Select statement does the anonymous method have to return a value? 在LINQ Select语句中使用匿名方法时,匿名方法是否必须返回值?

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 : 但是当我这样做时,我得到一个错误,提示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: 这是doSomething方法:

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.
}

When using an anonymous method in a LINQ Select statement does the anonymous method have to return a value? 在LINQ Select语句中使用匿名方法时,匿名方法是否必须返回值?

Yes. 是。 The signature of the Select method is: Select方法的签名为:

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. 在第一个代码段中,return语句是隐式的。 doSomething returns a value, and that value is what each item is projected to. doSomething返回一个值,该值就是每个项目的目标值。

When you use a statement lambda, instead of an expression lambda, there is no implicit return statement. 当您使用语句lambda而不是表达式lambda时,没有隐式return语句。 Since your second code block is not returning anything, it doesn't match what Select expects. 由于您的第二个代码块未返回任何内容,因此它与Select期望不符。

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. 您要做的是将每个任务投影到一个执行某项任务的任务中,然后在完成后写入日志并更新UI。 You can use an async lambda to do this. 您可以使用async lambda来执行此操作。 In an async lambda when there are no return statement it will still be returning a Task (just without a Result ) instead of void . async lambda中,当没有return语句时,它仍将返回Task (只是没有Result )而不是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();
}));

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. 是的,您传递给Select()的函数必须返回一个值,因为Select的目的是将一组值更改为另一组值。 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();
}));

The first one is a simple expression, so the type of that expression is used as the return type of the lambda. 第一个是简单表达式,因此该表达式的类型用作lambda的返回类型。

From MSDN : MSDN

A lambda expression with an expression on the right side of the => operator is called an expression lambda. 在=>运算符右侧具有表达式的lambda表达式称为表达式lambda。 Expression lambdas are used extensively in the construction of Expression Trees (C# and Visual Basic). 表达式lambda在表达式树(C#和Visual Basic)的构造中被广泛使用。 An expression lambda returns the result of the expression 表达式lambda返回表达式的结果

(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. 但是,您拥有的是lambda 语句 ,这意味着要返回值,您必须在lambda主体中具有return语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM