等待在可枚举上使用

xan*_*key 5 c# using async-await

我有一段代码,我想将using语句应用于commands可枚举中的每个命令。什么是 C# 语法?

await using var transaction = await conn.BeginTransactionAsync(cancel);
IEnumerable<DbCommand> commands = BuildSnowflakeCommands(conn, tenantId);

var commandTasks = new List<Task>();
foreach (var command in commands)
{
    command.CommandTimeout = commandTimeout;
    command.Transaction = transaction;
    commandTasks.Add(command.ExecuteNonQueryAsync(cancel));
}

try
{
    await Task.WhenAll(commandTasks);
}
catch (SnowflakeDbException)
{
    await transaction.RollbackAsync(cancel);
    return;
}

await transaction.CommitAsync(cancel);
Run Code Online (Sandbox Code Playgroud)

编辑:Rider / ReSharper 似乎认为这两个是等价的,或者至少我得到了将 the 转换for为 a的提示foreach(这显然是错误的):

for (var i = 0; i < commands.Count; i++)
{
    await using var command = commands[i];
    command.CommandTimeout = commandTimeout;
    command.Transaction = transaction;
    commandTasks.Add(command.ExecuteNonQueryAsync(cancel));
}
Run Code Online (Sandbox Code Playgroud)

foreach (var command in commands)
{
    command.CommandTimeout = commandTimeout;
    command.Transaction = transaction;
    commandTasks.Add(command.ExecuteNonQueryAsync(cancel));
}
Run Code Online (Sandbox Code Playgroud)

编辑 2:经过一些讨论和一些有用的答案后,这就是我要做的:

var transaction = await conn.BeginTransactionAsync(cancel);
var commands = BuildSnowflakeCommands(conn, tenantId);

var commandTasks = commands.Select(async command =>
{
    await using (command)
    {
        command.CommandTimeout = commandTimeout;
        command.Transaction = transaction;
        await command.ExecuteNonQueryAsync(cancel);
    }
});

try
{
    await Task.WhenAll(commandTasks);
    await transaction.CommitAsync(cancel);
}
catch (SnowflakeDbException)
{
    await transaction.RollbackAsync(cancel);
}
finally
{
    await transaction.DisposeAsync();
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*lay 5

您可以使用 LINQ:

var commandTasks = commands.Select(async command =>
{
    using (command)
    {
        command.CommandTimeout = commandTimeout;
        command.Transaction = transaction;
        await command.ExecuteNonQueryAsync(cancel);
    }
});
Run Code Online (Sandbox Code Playgroud)

该命令一旦退出作用域就会被处理。

完整代码:

await using var transaction = await conn.BeginTransactionAsync(cancel);
IEnumerable<DbCommand> commands = BuildSnowflakeCommands(conn, tenantId);

var commandTasks = commands.Select(async command =>
{
    using (command)
    {
        command.CommandTimeout = commandTimeout;
        command.Transaction = transaction;
        await command.ExecuteNonQueryAsync(cancel);
    }
});

try
{
    await Task.WhenAll(commandTasks);
}
catch (SnowflakeDbException)
{
    await transaction.RollbackAsync(cancel);
    return;
}

await transaction.CommitAsync(cancel);
Run Code Online (Sandbox Code Playgroud)

绝对不要使用for循环示例;这await将导致每个命令串行发生,因为必须等待每个查询完成才能启动下一个查询。

  • @xandermonkey 不,一旦点击“await”,“async” lambda 就会返回一个“Task”,从而允许每个命令并行发生。每个命令仅在“ExecuteNonQueryAsync”完成后才会被处理。 (2认同)