How to write an async method with out parameter?
How to write an async method with out parameter?
I want to write an async method with an out
parameter, like this:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
How do I do this in GetDataTaskAsync
?
回答1
You can't have async methods with ref
or out
parameters.
Lucian Wischik explains why this is not possible on this MSDN thread: http://social.msdn.microsoft.com/Forums/en-US/d2f48a52-e35a-4948-844d-828a1a6deb74/why-async-methods-cannot-have-ref-or-out-parameters
As for why async methods don't support out-by-reference parameters? (or ref parameters?) That's a limitation of the CLR. We chose to implement async methods in a similar way to iterator methods -- i.e. through the compiler transforming the method into a state-machine-object. The CLR has no safe way to store the address of an "out parameter" or "reference parameter" as a field of an object. The only way to have supported out-by-reference parameters would be if the async feature were done by a low-level CLR rewrite instead of a compiler-rewrite. We examined that approach, and it had a lot going for it, but it would ultimately have been so costly that it'd never have happened.
A typical workaround for this situation is to have the async method return a Tuple instead. You could re-write your method as such:
public async Task Method1()
{
var tuple = await GetDataTaskAsync();
int op = tuple.Item1;
int result = tuple.Item2;
}
public async Task<Tuple<int, int>> GetDataTaskAsync()
{
//...
return new Tuple<int, int>(1, 2);
}
评论
Far from being too complex, this could produce too many problem. Jon Skeet explained it very well here stackoverflow.com/questions/20868103/…
回答2
The C#7+ Solution is to use implicit tuple syntax.
private async Task<(bool IsSuccess, IActionResult Result)> TryLogin(OpenIdConnectRequest request)
{
return (true, BadRequest(new OpenIdErrorResponse
{
Error = OpenIdConnectConstants.Errors.AccessDenied,
ErrorDescription = "Access token provided is not valid."
}));
}
return result utilizes the method signature defined property names. e.g:
var foo = await TryLogin(request);
if (foo.IsSuccess)
return foo.Result;
回答3
You cannot have ref
or out
parameters in async
methods (as was already noted).
This screams for some modelling in the data moving around:
public class Data
{
public int Op {get; set;}
public int Result {get; set;}
}
public async void Method1()
{
Data data = await GetDataTaskAsync();
// use data.Op and data.Result from here on
}
public async Task<Data> GetDataTaskAsync()
{
var returnValue = new Data();
// Fill up returnValue
return returnValue;
}
You gain the ability to reuse your code more easily, plus it's way more readable than variables or tuples.
作者:Chuck Lu GitHub |