Open andypennell opened 9 years ago
The work-around is to add ".Result" on the end of the expression. GetResult isn't unwrapping the Task correctly, though it looks correct in the Runtime source.
async () => { return await AFunc(); })
returns a Task<int>
.
Task.Run(async () => { return await AFunc(); })
returns a Task<Task<int>>
.
Task.Run(async () => { return await AFunc(); }).GetAwaiter().GetResult()
returns a Task<int>
.
There seems to be a Task.Run<T>(Func<Task<T>> function)
in standard .net, which I didn't know existed and therefore is not in the metadata. But I don't think it would be very useful anyway.
I am not so sure that is the cause. Try this code:
var a = Task.Run(async () => { return await AFunc(); });
var b = a.GetAwaiter();
var c = b.GetResult();
int d = c;
Compared to .NET the types of a and b are the same, but c is not so the assignment to d fails.
(FYI this pattern is a popular way to add an async call into a non-async method and block until it is done)
The difference is that .net has an overload Task<T> Task.Run<T>(Func<Task<T>> function)
, but this overload is not in Saltarelle's custom mscorlib, so instead Task<T> Task.Run<T>(Func<T> function)
will get invoked (with T
being Task<int>
, so the return type is Task<Task<int>>
). I believe the purpose of the .net overload is to run the specified task on the threadpool synchronization context instead of on the syncronization context from which the call was made, but this need does not exist in JS (since there is only one thread anyway).
What is your reason for not just doing
var a = AFunc();
var b = a.GetAwaiter();
var c = b.GetResult();
int d = c;
?
I guess for completeness, the Run<T>(Func<Task<T>>)
overload should be added, but I see it being implemented as just
[InlineCode("{func}()")]
public static Task<TResult> Run<TResult>(Func<Task<TResult>> func) {}
so it doesn't really serve any purpose except source code compatibility with .net
Btw, I just saw that in the MSDN page for the overload you are using (http://msdn.microsoft.com/en-us/library/hh194918(v=vs.110).aspx) it says
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.
Ah, interesting. Yes, I am attempting to port a large existing codebase, so keeping the source as compatible as possible is a requirement. This pattern is being used in catch blocks (as await cannot be done there), which I don't think is a good idea generally, so I think I will refactor this code anyway. Thank you for your prompt replies.
gives error CS0029: Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'int'
Something hasn't "unwrapped" the Task. Note that I already added the extra { }s to avoid a reported problem with async lambdas.