Tout d'abord, les réponses de Henk et Olivier sont correctes; Je veux l'expliquer d'une manière légèrement différente. Plus précisément, je veux parler de ce que vous avez soulevé. Vous avez cet ensemble d'instructions:
int k = 10;
int c = 30;
k += c += k += c;
Et vous concluez alors à tort que cela devrait donner le même résultat que cet ensemble d'instructions:
int k = 10;
int c = 30;
k += c;
c += k;
k += c;
Il est instructif de voir comment vous vous êtes trompé et comment le faire correctement. La bonne façon de le décomposer est comme ça.
Tout d'abord, réécrivez le + =
k = k + (c += k += c);
Deuxièmement, réécrivez le + extérieur. J'espère que vous êtes d'accord que x = y + z doit toujours être la même chose que "évaluer y à un temporaire, évaluer z à un temporaire, additionner les temporaires, affecter la somme à x" . Alors, rendons cela très explicite:
int t1 = k;
int t2 = (c += k += c);
k = t1 + t2;
Assurez-vous que ce soit clair, car c'est l'étape que vous avez mal . Lorsque vous décomposez des opérations complexes en opérations plus simples, vous devez vous assurer de le faire lentement et prudemment et de ne pas sauter d'étapes . Sauter des étapes est l'endroit où nous commettons des erreurs.
OK, maintenant décomposez l'affectation à t2, encore une fois, lentement et soigneusement.
int t1 = k;
int t2 = (c = c + (k += c));
k = t1 + t2;
L'affectation attribuera la même valeur à t2 qu'à c, donc disons que:
int t1 = k;
int t2 = c + (k += c);
c = t2;
k = t1 + t2;
Génial. Maintenant, décomposez la deuxième ligne:
int t1 = k;
int t3 = c;
int t4 = (k += c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Super, nous progressons. Décomposez l'affectation en t4:
int t1 = k;
int t3 = c;
int t4 = (k = k + c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Maintenant, décomposez la troisième ligne:
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Et maintenant, nous pouvons tout regarder:
int k = 10; // 10
int c = 30; // 30
int t1 = k; // 10
int t3 = c; // 30
int t4 = k + c; // 40
k = t4; // 40
int t2 = t3 + t4; // 70
c = t2; // 70
k = t1 + t2; // 80
Donc, lorsque nous avons terminé, k est 80 et c est 70.
Voyons maintenant comment cela est implémenté dans l'IL:
int t1 = k;
int t3 = c;
is implemented as
ldloc.0 // stack slot 1 is t1
ldloc.1 // stack slot 2 is t3
Maintenant, c'est un peu délicat:
int t4 = k + c;
k = t4;
is implemented as
ldloc.0 // load k
ldloc.1 // load c
add // sum them to stack slot 3
dup // t4 is stack slot 3, and is now equal to the sum
stloc.0 // k is now also equal to the sum
Nous aurions pu implémenter ce qui précède comme
ldloc.0 // load k
ldloc.1 // load c
add // sum them
stloc.0 // k is now equal to the sum
ldloc.0 // t4 is now equal to k
mais nous utilisons l'astuce "dup" car elle rend le code plus court et facilite la gigue, et nous obtenons le même résultat. En général, le générateur de code C # essaie de garder les temporaires "éphémères" sur la pile autant que possible. Si vous trouvez qu'il est plus facile de suivre l'IL avec moins Ephémères, optimisations tour off , et le générateur de code sera moins agressif.
Nous devons maintenant faire la même chose pour obtenir c:
int t2 = t3 + t4; // 70
c = t2; // 70
is implemented as:
add // t3 and t4 are the top of the stack.
dup
stloc.1 // again, we do the dup trick to get the sum in
// both c and t2, which is stack slot 2.
et enfin:
k = t1 + t2;
is implemented as
add // stack slots 1 and 2 are t1 and t2.
stloc.0 // Store the sum to k.
Puisque nous n'avons besoin de la somme pour rien d'autre, nous ne la dupons pas. La pile est maintenant vide et nous sommes à la fin de l'instruction.
La morale de l'histoire est la suivante: lorsque vous essayez de comprendre un programme complexe, décomposez toujours les opérations une par une . Ne prenez pas de raccourcis; ils vous égareront.