No. It isn't. This ForEach
doesn't support async-await
and requires your lambda to be async void
which should only be used for event handlers. Using it will run all your async
operations concurrently and won't wait for them to complete.
You can use a regular foreach
as you did but if you want an extension method you need a special async
version.
You can create one yourself that iterates over the items, executes an async
operation and await
s it:
public async Task ForEachAsync<T>(this IEnumerable<T> enumerable, Func<T, Task> action)
{
foreach (var item in enumerable)
{
await action(item);
}
}
Usage:
internal static async Task AddReferencseData(ConfigurationDbContext context)
{
await RequiredSinkTypeList.ForEachAsync(async sinkName =>
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
});
}
A different (and usually more efficient) implementation of ForEachAsync
would be to start all the async
operations and only then await
all of them together but that's only possible if your actions can run concurrently which isn't always the case (e.g. Entity Framework):
public Task ForEachAsync<T>(this IEnumerable<T> enumerable, Func<T, Task> action)
{
return Task.WhenAll(enumerable.Select(item => action(item)));
}
As was noted in the comments you probably don't want to use SaveChangesAsync
in a foreach to begin with. Preparing your changes and then saving them all at once will probably be more efficient.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…