Issue
Microsoft's documentation states:
Any lambda expression can be converted to a delegate type. The delegate type to which a lambda expression can be converted is defined by the types of its parameters and return value. If a lambda expression doesn't return a value, it can be converted to one of the
Actiondelegate types; otherwise, it can be converted to one of theFuncdelegate types.
(https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions)
This documentation, though, does not explain the behavior of async lambda expressions, specifically ones lacking any return statement, being converted to delegate values.
If you are trying to convert to a Func<Task>, the conversion succeeds.
If you are trying to convert to an Action, the conversion succeeds and the anonymous method emitted for the lambda is async void.
If both Action and Func<Task> are options, then the compiler selects Func<Task>.
This all makes sense, but where is it specified? Per the above paragraph, it shouldn't work this way. The paragraph quoted above doesn't allow for async methods that don't return a value having a return type of Task. I've done some searching and haven't found anything covering this. It must be out there, though, right? :-)
Solution
That language reference isn't really the spec, although it's reasonably "spec-like".
The relevant section of the draft C# 7 spec on the Microsoft site is here, based on the ECMA standard GitHub repo with the section here.
The relevant bullets in 10.7.1 for the conditions under which "an anonymous function F is compatible with a delegate type D" are:
- If the body of
Fis an expression, and eitherDhas a void return type orFis async andDhas the return typeTask, then when each parameter ofFis given the type of the corresponding parameter inD, the body ofFis a valid expression (w.r.t §11) that would be permitted as a statement_expression (§12.7).- If the body of
Fis a block, and eitherDhas a void return type or F is async andDhas the return typeTask, then when each parameter ofFis given the type of the corresponding parameter inD, the body ofFis a valid block (w.r.t §12.3) in which noreturnstatement specifies an expression.
Those are met for both Action and Func<Task> when considering an async lambda expression with no parameters and no return statements which specify expressions.
The fact that the conversion to Func<Task> is deemed better than the conversion to Action looks like it may be missing at the moment. I've raised a bug for this; it may be that there's something I've overlooked though (or that it wasn't specified in C# 7, and has been improved since then).
Answered By - Jon Skeet Answer Checked By - Timothy Miller (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.