我想写一个带out参数的async方法,像这样:

public async void Method1()
{
    int op;
    int result = await GetDataTaskAsync(out op);
}

我如何做到这一点在GetDataTaskAsync?


当前回答

您可以通过使用TPL(任务并行库)而不是直接使用await关键字来做到这一点。

private bool CheckInCategory(int? id, out Category category)
    {
        if (id == null || id == 0)
            category = null;
        else
            category = Task.Run(async () => await _context.Categories.FindAsync(id ?? 0)).Result;

        return category != null;
    }

if(!CheckInCategory(int? id, out var category)) return error

其他回答

c# 7+的解决方案是使用隐式元组语法。

    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."
        }));
    }

返回结果使用方法签名定义的属性名。例句:

var foo = await TryLogin(request);
if (foo.IsSuccess)
     return foo.Result;

Alex在可读性上有很好的观点。同样,函数也具有足够的接口来定义返回的类型,并且还可以获得有意义的变量名。

delegate void OpDelegate(int op);
Task<bool> GetDataTaskAsync(OpDelegate callback)
{
    bool canGetData = true;
    if (canGetData) callback(5);
    return Task.FromResult(canGetData);
}

调用者提供一个lambda(或一个命名函数),智能感知通过从委托复制变量名来提供帮助。

int myOp;
bool result = await GetDataTaskAsync(op => myOp = op);

这种特殊的方法类似于“Try”方法,如果方法结果为真,则设置myOp。否则,你不会关心myOp。

在异步方法中不能有ref或out参数(如前所述)。

这需要在数据移动中进行一些建模:

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

您获得了更容易重用代码的能力,而且它比变量或元组更具可读性。

模式匹配来拯救!c# 9(我认为)之后:

// example of a method that would traditionally would use an out parameter
public async Task<(bool success, int? value)> TryGetAsync()
{
    int? value = // get it from somewhere
    
    return (value.HasValue, value);
}

像这样使用它:

if (await TryGetAsync() is (true, int value))
{
    Console.WriteLine($"This is the value: {value}");
}

您可以通过使用TPL(任务并行库)而不是直接使用await关键字来做到这一点。

private bool CheckInCategory(int? id, out Category category)
    {
        if (id == null || id == 0)
            category = null;
        else
            category = Task.Run(async () => await _context.Categories.FindAsync(id ?? 0)).Result;

        return category != null;
    }

if(!CheckInCategory(int? id, out var category)) return error