Prima di tutto, le risposte di Henk e Olivier sono corrette; Voglio spiegarlo in un modo leggermente diverso. In particolare, voglio affrontare questo punto che hai sollevato. Hai questo insieme di affermazioni:
int k = 10;
int c = 30;
k += c += k += c;
E poi concludi erroneamente che questo dovrebbe dare lo stesso risultato di questo insieme di affermazioni:
int k = 10;
int c = 30;
k += c;
c += k;
k += c;
È informativo vedere come hai sbagliato e come farlo nel modo giusto. Il modo giusto per scomporlo è così.
Innanzitutto, riscrivi il + = più esterno
k = k + (c += k += c);
Secondo, riscrivi il + più esterno. Spero che tu sia d'accordo sul fatto che x = y + z deve sempre essere uguale a "valuta y come temporaneo, valuta z come temporaneo, somma i provvisori, assegna la somma ax" . Quindi rendiamolo molto esplicito:
int t1 = k;
int t2 = (c += k += c);
k = t1 + t2;
Assicurati che sia chiaro, perché questo è il passaggio che hai sbagliato . Quando si suddividono operazioni complesse in operazioni più semplici, è necessario assicurarsi di farlo lentamente e con attenzione e di non saltare i passaggi . Saltare i passaggi è dove commettiamo errori.
OK, ora scomponi il compito di t2, di nuovo, lentamente e con attenzione.
int t1 = k;
int t2 = (c = c + (k += c));
k = t1 + t2;
L'assegnazione assegnerà a t2 lo stesso valore assegnato a c, quindi diciamo che:
int t1 = k;
int t2 = c + (k += c);
c = t2;
k = t1 + t2;
Grande. Ora scomponi la seconda riga:
int t1 = k;
int t3 = c;
int t4 = (k += c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Fantastico, stiamo facendo progressi. Suddividi l'assegnazione a t4:
int t1 = k;
int t3 = c;
int t4 = (k = k + c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Ora abbatti la terza riga:
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
E ora possiamo guardare tutto:
int k = 10;
int c = 30;
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Quindi, quando abbiamo finito, k è 80 ec è 70.
Ora diamo un'occhiata a come questo viene implementato nell'IL:
int t1 = k;
int t3 = c;
is implemented as
ldloc.0
ldloc.1
Ora questo è un po 'complicato:
int t4 = k + c;
k = t4;
is implemented as
ldloc.0
ldloc.1
add
dup
stloc.0
Avremmo potuto implementare quanto sopra come
ldloc.0
ldloc.1
add
stloc.0
ldloc.0
ma usiamo il trucco "dup" perché rende il codice più corto e facilita il jitter, e otteniamo lo stesso risultato. In generale, il generatore di codice C # cerca di mantenere i provvisori "temporanei" nello stack il più possibile. Se si trova più facile seguire l'IL con un minor numero di ephemerals, girare ottimizzazioni off , e il generatore di codice sarà meno aggressivo.
Ora dobbiamo fare lo stesso trucco per ottenere c:
int t2 = t3 + t4;
c = t2;
is implemented as:
add
dup
stloc.1
e infine:
k = t1 + t2;
is implemented as
add
stloc.0
Poiché non abbiamo bisogno della somma per nient'altro, non la duplichiamo. Lo stack è ora vuoto e siamo alla fine dell'istruzione.
La morale della storia è: quando cerchi di capire un programma complicato, interrompi sempre le operazioni una alla volta . Non prendere scorciatoie; ti porteranno fuori strada.