En primer lugar, las respuestas de Henk y Olivier son correctas; Quiero explicarlo de una manera ligeramente diferente. Específicamente, quiero abordar este punto que hizo. Tienes este conjunto de declaraciones:
int k = 10;
int c = 30;
k += c += k += c;
Y luego concluye incorrectamente que esto debería dar el mismo resultado que este conjunto de declaraciones:
int k = 10;
int c = 30;
k += c;
c += k;
k += c;
Es informativo ver cómo se equivocó y cómo hacerlo bien. La forma correcta de descomponerlo es así.
Primero, reescribe el más externo + =
k = k + (c += k += c);
En segundo lugar, reescribe el + más externo. Espero que esté de acuerdo en que x = y + z siempre debe ser lo mismo que "evaluar y como temporal, evaluar z como temporal, sumar los temporales, asignar la suma ax" . Así que hagámoslo muy explícito:
int t1 = k;
int t2 = (c += k += c);
k = t1 + t2;
Asegúrese de que esté claro, porque este es el paso que se equivocó . Al dividir operaciones complejas en operaciones más simples, debe asegurarse de hacerlo lenta y cuidadosamente y de no omitir pasos . Saltar pasos es donde cometemos errores.
Bien, ahora divida la asignación en t2, nuevamente, lenta y cuidadosamente.
int t1 = k;
int t2 = (c = c + (k += c));
k = t1 + t2;
La asignación asignará el mismo valor a t2 que a c, así que digamos que:
int t1 = k;
int t2 = c + (k += c);
c = t2;
k = t1 + t2;
Excelente. Ahora analice la segunda línea:
int t1 = k;
int t3 = c;
int t4 = (k += c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Genial, estamos progresando. Divida la asignación en t4:
int t1 = k;
int t3 = c;
int t4 = (k = k + c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Ahora analice la tercera línea:
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Y ahora podemos ver todo:
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;
Entonces, cuando terminamos, k es 80 y c es 70.
Ahora veamos cómo se implementa esto en IL:
int t1 = k;
int t3 = c;
is implemented as
ldloc.0
ldloc.1
Ahora bien, esto es un poco complicado:
int t4 = k + c;
k = t4;
is implemented as
ldloc.0
ldloc.1
add
dup
stloc.0
Podríamos haber implementado lo anterior como
ldloc.0
ldloc.1
add
stloc.0
ldloc.0
pero usamos el truco "dup" porque acorta el código y facilita el jitter, y obtenemos el mismo resultado. En general, el generador de código C # intenta mantener los temporales "efímeros" en la pila tanto como sea posible. Si le resulta más fácil seguir la IL con menos efímeras, a su vez optimizaciones fuera , y el generador de código será menos agresivo.
Ahora tenemos que hacer el mismo truco para obtener c:
int t2 = t3 + t4;
c = t2;
is implemented as:
add
dup
stloc.1
y finalmente:
k = t1 + t2;
is implemented as
add
stloc.0
Como no necesitamos la suma para nada más, no la duplicamos. La pila ahora está vacía y estamos al final de la declaración.
La moraleja de la historia es: cuando intente comprender un programa complicado, siempre analice las operaciones una por una . No tome atajos; te llevarán por mal camino.