S'il vous plaît, considérez le code exemple suivant:Comment gérer les effets secondaires produits par async/await lorsqu'il s'agit de types de valeurs mutables?
using System.Diagnostics;
using System.Threading.Tasks;
public struct AStruct
{
public int Value;
public async Task SetValueAsync()
{
Value = await Task.Run(() => 1);
}
public void SetValue()
{
Value = 1;
}
}
class Program
{
static void Main(string[] args)
{
Test(new AStruct());
TestAsync(new AStruct()).Wait();
}
private static async Task TestAsync(AStruct x)
{
Debug.Assert(x.Value == 0);
await x.SetValueAsync();
Debug.Assert(x.Value == 0);
}
private static void Test(AStruct x)
{
Debug.Assert(x.Value == 0);
x.SetValue();
Debug.Assert(x.Value == 1);
}
}
Notez la différence entre Test
et TestAsync
. Ce code satisfait toutes les affirmations. Je suppose que regarder le code avec Reflector me dira pourquoi, mais c'est quelque chose que je ne m'attendais pas du tout.
Bien sûr, changer AStruct
pour être une classe au lieu d'une structure échoue la deuxième assertion en TestAsync
- comme je l'attendrais en premier lieu.
Ma question est la suivante - en plus de ne pas utiliser des structures mutables avec async/await, y at-il une manière élégante de les faire coexister pacifiquement?
La mutation d'un type de valeur lorsqu'il s'agit d'un paramètre (sans 'ref') est totalement absurde. Async ne vient même pas dans cette image. – leppie
@leppie Le problème est que SetValueAsync ne mute pas la variable qui l'appelle, et ce n'est pas le cas précisément parce que c'est une méthode 'async'. Le fait qu'il soit appelé sur une variable qui est un paramètre qui n'est pas passé par 'ref' n'est pas du tout pertinent. La mutation ne parvient même pas à faire muter la copie que 'TestAsync' fait de la structure créée dans' Main'. – Servy
@Servy: Devinez la même chose ira pour un générateur (et probablement lors de l'utilisation d'une variable libre). – leppie