Po pierwsze, odpowiedzi Henka i Oliviera są poprawne; Chcę to wyjaśnić w nieco inny sposób. W szczególności chciałbym odnieść się do tego, co przedstawiłeś. Masz ten zestaw instrukcji:
int k = 10;
int c = 30;
k += c += k += c;
I wtedy błędnie dochodzisz do wniosku, że powinno to dać taki sam wynik jak ten zestaw instrukcji:
int k = 10;
int c = 30;
k += c;
c += k;
k += c;
Warto zobaczyć, jak się pomyliłeś i jak to zrobić dobrze. Właściwy sposób na rozbicie tego jest taki.
Najpierw przepisz najbardziej zewnętrzny + =
k = k + (c += k += c);
Po drugie, przepisz najbardziej zewnętrzny znak +. Mam nadzieję, że zgodzisz się, że x = y + z musi zawsze być tym samym, co „oszacuj y na tymczasowe, oszacuj z na tymczasowe, zsumuj tymczasowe, przypisz sumę do x” . Zróbmy to bardzo wyraźnie:
int t1 = k;
int t2 = (c += k += c);
k = t1 + t2;
Upewnij się, że jest to jasne, ponieważ jest to krok, który popełniłeś źle . Rozbijając złożone operacje na prostsze, musisz upewnić się, że robisz to powoli i ostrożnie oraz nie pomijaj poszczególnych kroków . Pomijanie kroków jest tym, gdzie popełniamy błędy.
OK, teraz ponownie, powoli i ostrożnie, podziel przypisanie na t2.
int t1 = k;
int t2 = (c = c + (k += c));
k = t1 + t2;
Przypisanie przypisze tę samą wartość do t2, jaka jest przypisana do c, więc powiedzmy, że:
int t1 = k;
int t2 = c + (k += c);
c = t2;
k = t1 + t2;
Świetny. Teraz podziel drugą linię:
int t1 = k;
int t3 = c;
int t4 = (k += c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Świetnie, robimy postępy. Podziel przypisanie do t4:
int t1 = k;
int t3 = c;
int t4 = (k = k + c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Teraz podziel trzecią linię:
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
A teraz możemy spojrzeć na całość:
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;
Więc kiedy skończymy, k wynosi 80, a c wynosi 70.
Teraz spójrzmy, jak to jest zaimplementowane w IL:
int t1 = k;
int t3 = c;
is implemented as
ldloc.0
ldloc.1
Teraz jest to trochę trudne:
int t4 = k + c;
k = t4;
is implemented as
ldloc.0
ldloc.1
add
dup
stloc.0
Mogliśmy zaimplementować powyższe jako
ldloc.0
ldloc.1
add
stloc.0
ldloc.0
ale używamy sztuczki „dup”, ponieważ sprawia, że kod jest krótszy i łatwiejszy w przypadku jittera, i otrzymujemy ten sam wynik. Ogólnie rzecz biorąc, generator kodu C # stara się zachować jak najwięcej tymczasowych „efemerycznych” na stosie. Jeśli okaże się, że łatwiej śledzić IL mniej ephemerals skręcić optymalizacji off , a generator kodu będzie mniej agresywny.
Teraz musimy zrobić tę samą sztuczkę, aby uzyskać c:
int t2 = t3 + t4;
c = t2;
is implemented as:
add
dup
stloc.1
i w końcu:
k = t1 + t2;
is implemented as
add
stloc.0
Ponieważ nie potrzebujemy kwoty do niczego innego, nie oszukujemy jej. Stos jest teraz pusty, a my jesteśmy na końcu instrukcji.
Morał tej historii jest taki: kiedy próbujesz zrozumieć skomplikowany program, zawsze wykonuj operacje pojedynczo . Nie idź na skróty; sprowadzą cię na manowce.