C# async attendent à l'aide de LINQ ForEach()
J'ai le code suivant qui utilise correctement async/await paradigme.
internal static async Task AddReferencseData(ConfigurationDbContext context)
{
foreach (var sinkName in RequiredSinkTypeList)
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
}
}
Ce qui est l'équivalent de la façon d'écrire ce si, au lieu d'utiliser foreach(), je veux utiliser LINQ ForEach()? Celle-ci, par exemple, donne une erreur de compilation.
internal static async Task AddReferenceData(ConfigurationDbContext context)
{
RequiredSinkTypeList.ForEach(
sinkName =>
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
});
}
Le seul code que j'ai eu à travailler sans erreur de compilation est ce.
internal static void AddReferenceData(ConfigurationDbContext context)
{
RequiredSinkTypeList.ForEach(
async sinkName =>
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
});
}
Je suis inquiet que cette méthode n'a pas de async signature, seulement le corps ne.
Est-ce le bon équivalent de mon premier bloc de code ci-dessus?
ForEach
pas une fonction de linq- Pourquoi voulez-vous changer? Si elle n'est pas cassé, ne le répare pas.
- Excellent post d'Eric Lipert à l'aide de “foreach” vs “ForEach” blogs.msdn.com/b/ericlippert/archive/2009/05/18/...
- Si j'allais faire quelque chose, je mettrais l'
SaveChangesAsync
en dehors de la boucle. Je doute qu'il n'y a aucun avantage à le mettre à l'intérieur (au contraire, il y a probablement une perte de performance). - Mager en effet - c'est presque toujours une mauvaise idée de mettre
SaveChanges()
dans une boucle. Sur l'autre remarque, pourquoi êtes-vous en invoquant la async version exactement?
Vous devez vous connecter pour publier un commentaire.
Pas. Il n'est pas. Cette
ForEach
ne prend pas en chargeasync-await
et exige votre lambda êtreasync void
qui devrait seulement être utilisé pour les gestionnaires d'événements. Il vous permettra de exécuter tous vosasync
opérations simultanément et de ne pas attendre pour eux de complet.Vous pouvez utiliser un
foreach
comme vous l'avez fait, mais si vous voulez une méthode d'extension vous besoin d'une spécialeasync
version.Vous pouvez en créer un vous-même qui effectue une itération sur les éléments, exécute un
async
fonctionnement etawait
s il:Utilisation:
À un autre (et souvent plus efficace) de la mise en œuvre de
ForEachAsync
serait de commencer tous lesasync
opérations, et seulement alors,await
tous ensemble, mais ce n'est possible que si vos actions peuvent s'exécuter simultanément, ce qui n'est pas toujours le cas (par exemple, Entity Framework):Comme cela a été noté dans les commentaires, vous ne voulez probablement pas à utiliser
SaveChangesAsync
dans un foreach pour commencer. La préparation de vos modifications, puis de les enregistrer à la fois sera probablement plus efficace.SaveChangesAsync
.À écrire vous attendent dans une méthode de votre méthode doit être marqué comme async.
Lorsque vous écrivez un ForEach méthode que vous écrivez vous attendent à l'intérieur de votre labda expression qui est différente de la méthode complètement que vous appelez à partir de votre méthode. Vous avez besoin de déplacer ce lamdba expression à la méthode et à la marque que la méthode asynchrone et aussi comme @i3arnon dit, Vous avez besoin async marqué ForEach méthode qui n'est pas encore prévu par .Net Framework. Si vous avez besoin de l'écrire sur votre propre.
Le premier exemple avec
foreach
efficacement attend après chaque itération de boucle.Le dernier exemple invoque
List<T>.ForEach()
qui prend unAction<T>
sens, que vos lambda asynchrone de compiler dans unvoid
délégué, par opposition à la normeTask
.Effectivement, le
ForEach()
méthode invoke "itérations", un par un, sans attendre, pour chacun, à la fin. Cela permettra également de se propager à votre méthode, ce qui signifie queAddReferenceData()
peut se terminer avant la fin des travaux.Donc non, ce n'est pas un équivalent et se comporte tout à fait différemment. En fait, en supposant que c'est un EF contexte, elle va se faire sauter comme il ne peut pas être utilisé sur plusieurs threads simultanément.
Également lire http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx mentionné par Deepu pour pourquoi il est probablement préférable de s'en tenir à
foreach
.Pourquoi ne pas utiliser AddRange() la méthode?
Merci à tous pour vos commentaires. En prenant le "enregistrer" partie en dehors de la boucle, je crois que les 2 méthodes suivantes sont désormais équivalents, l'un utilisant
foreach()
, l'autre à l'aide.ForEach()
. Cependant, comme mentionné par Deepu, je vais lire Eric post sur pourquoiforeach
peut-être mieux.