По-перше, відповіді Хенка та Олів’є правильні; Я хочу пояснити це дещо по-іншому. Зокрема, я хочу розглянути це питання, яке ви зробили. У вас є такий набір тверджень:
int k = 10;
int c = 30;
k += c += k += c;
І ви неправильно робите висновок, що це повинно давати той самий результат, що і цей набір тверджень:
int k = 10;
int c = 30;
k += c;
c += k;
k += c;
Інформативно побачити, як ви зробили таку помилку і як це правильно зробити. Правильний спосіб його розбити - такий.
Спочатку перепишіть зовнішній + =
k = k + (c += k += c);
По-друге, перепишіть крайній +. Сподіваюсь, ви погоджуєтесь з тим, що x = y + z завжди має збігатися з "оцінити y тимчасовим, оцінити z тимчасовим, підсумувати тимчасові, призначити суму х" . Тож давайте зробимо це дуже явним:
int t1 = k;
int t2 = (c += k += c);
k = t1 + t2;
Переконайтеся, що це зрозуміло, адже це крок, який ви помилилися . Розбиваючи складні операції на більш прості, ви повинні переконатися, що робите це повільно та обережно і не пропускаєте кроки . Пропускаючи кроки, ми робимо помилки.
Добре, тепер розбийте призначення на t2, ще раз, повільно і обережно.
int t1 = k;
int t2 = (c = c + (k += c));
k = t1 + t2;
Присвоєння присвоює тому самому значенню t2, що і присвоєне c, тож припустимо, що:
int t1 = k;
int t2 = c + (k += c);
c = t2;
k = t1 + t2;
Чудово. Тепер розбийте другий рядок:
int t1 = k;
int t3 = c;
int t4 = (k += c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Чудово, ми робимо прогрес. Розбийте призначення на t4:
int t1 = k;
int t3 = c;
int t4 = (k = k + c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
Тепер розбийте третій рядок:
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
І тепер ми можемо поглянути на все це:
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;
Отже, коли ми закінчимо, k дорівнює 80, а c дорівнює 70.
Тепер давайте розглянемо, як це реалізовано в ІЛ:
int t1 = k;
int t3 = c;
is implemented as
ldloc.0
ldloc.1
Зараз це трохи хитро:
int t4 = k + c;
k = t4;
is implemented as
ldloc.0
ldloc.1
add
dup
stloc.0
Ми могли б реалізувати вищезазначене як
ldloc.0
ldloc.1
add
stloc.0
ldloc.0
але ми використовуємо трюк "dup", оскільки це робить код коротшим і полегшує тремтіння, і ми отримуємо той самий результат. Взагалі, генератор коду C # намагається тримати тимчасові "швидкоплинні" у стосі, наскільки це можливо. Якщо вам легше стежити за ІЛ із меншою кількістю ефемер, увімкніть оптимізацію від , і генератор коду буде менш агресивним.
Тепер нам потрібно зробити той самий трюк, щоб отримати c:
int t2 = t3 + t4;
c = t2;
is implemented as:
add
dup
stloc.1
і, нарешті:
k = t1 + t2;
is implemented as
add
stloc.0
Оскільки нам не потрібна сума ні для чого іншого, ми не дублюємо її. Зараз стек порожній, і ми в кінці заяви.
Мораль історії така: коли ви намагаєтеся зрозуміти складну програму, завжди розбивайте операції по черзі . Не слід робити короткі скорочення; вони заблукають вас.