我有一个代码块,我想在其中应用 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();
}
你可以使用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
将导致每个命令以串行方式发生,因为在下一个查询启动之前,必须等待每个查询的完成。
你不能调用 Dispose
或 DisposeAsync
一套 IDisposable
或 IAsyncDisposable
的语言语法。
你可以对每个命令进行迭代,然后调用相应的方法。 在重新枚举之前,我会将所有的命令缓存为一个数组或只读集合。
我会避免像你的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();
}