等候使用在可数上

问题描述 投票:0回答:1

我有一个代码块,我想在其中应用 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);

编辑:Rider ReSharper似乎认为这两个是等价的,或者说至少我得到了一个提示,让我转换了 for 变成 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));
}

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

编辑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();
}
c# async-await using
1个回答
4
投票

你可以使用LINQ。

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

一旦命令退出作用域,它就会被处理掉。

完整的代码。

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

绝对不要使用 for 循环的例子;的 await 将导致每个命令以串行方式发生,因为在下一个查询启动之前,必须等待每个查询的完成。


1
投票

你不能调用 DisposeDisposeAsync 一套 IDisposableIAsyncDisposable的语言语法。

你可以对每个命令进行迭代,然后调用相应的方法。 在重新枚举之前,我会将所有的命令缓存为一个数组或只读集合。

我会避免像你的JetBrains工具推荐的那样在你的循环中进行处置。命令要活得更久,而不仅仅是这样。

就个人而言,我会做这样的事情。

var commands = BuildSnowflakeCommands(conn, tenantId).ToArray();
var commandTasks = new List<Task>(commands.Length);

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

/// later...
foreach (var command in commands)
{
    command.Dispose();
}
© www.soinside.com 2019 - 2024. All rights reserved.