How many times can you spot the letter ё in:
Q: почему постфиксный оператор не выполняется раньше всего? int a = 1;
a = ++a * a++;
int b = 1;
b = b++ * ++b;

Почему a = 4, b = 3?
Приоритет у постфиксного оператора же больше, значит он выполнится до префиксного и умножения. Разве не так?

A: Приоритет никак не связан с порядком операций. Приоритеты лишь позволяют иногда (если они подобраны хорошо, то часто) писать без скобок.
В C# правило следующее: выражения вычисляются строго (с точностью до as-if-правила) слева направо. Точнее, строится дерево выражения, и обход его производится в обратном порядке: левое поддерево, затем правое поддерево, затем сам узел.
Выражение a = ++a * a++ даёт такое дерево:
        assign
        /    \
      a(1)    *
            /   \
  preincrement  postincrement
          /       \
        a(2)      a(3)

Вычисление:

*

*Вычисляем корневой узел assign, для этого:

*Вычисляем адрес a (1).

*Начинаем вычислять правый аргумент присваивания, для этого:

*Начинаем вычислять преинкремент, для этого:

*Вычисляем адрес a (2)

*Выполняем преинкремент (a становится равным 2, значение узла 2).

*Начинаем вычислять постинкремент, для этого:

*Берём снова адрес a (3)

*Выполняем постинкремент (a становится равным 3, значение узла 2).

*Умножение даёт 4.

*Выполняем присваивание, a становится равным 4.

Выражение b = b++ * ++b даёт такое дерево:
        assign
        /    \
      b(1)    *
            /   \
 postincrement  preincrement
          /       \
        b(2)      b(3)

Вычисление:

*

*Вычисляем корневой узел assign, для этого:

*Вычисляем адрес b (1).

*Начинаем вычислять правый аргумент присваивания, для этого:

*Начинаем вычислять постинкремент, для этого:

*Вычисляем адрес b (2)

*Выполняем постинкремент (b становится равным 2, значение узла 1).

*Начинаем вычислять преинкремент, для этого:

*Берём снова адрес b (3)

*Выполняем преинкремент (b становится равным 3, значение узла 3).

*Умножение даёт 3.

*Выполняем присваивание, b становится равным 3.


Дополнительное чтение по теме: Eric Lippert. Precedence vs associativity vs order.
Ещё один забавный пример тут.

В отличие от C#, в некоторых других языках (например, C++) порядок вычисления может быть не определён, а выражения наподобие тех, которые вы привели, могут приводить и вовсе к неопределённому поведению.

A: Да вроде всё логично.
int a = 1;
a = ++a * a++;

Оператор ++a увеличивает a и возвращает увеличенное значение.
А оператор a++ наоборот - сначала возвращает значение, а потом увеличивает a.
Что мы имеем, т.е. что возвращает инкремент и чему после этого равно a:
a = ++a * a++;
    ^^^   ^^^
   2(a=2) 2(a=3)

После a++ в a будет 3, но это значение тут же затрётся после присваивания результата a = 2 * 2, поэтому в a будет 4.
int b = 1;
b = b++ * ++b;
    ^^^   ^^^
   1(b=2) 3(b=3)

Тут в b и так уже 3 после двух инкрементов, и после присваивания результата вычисления b = 1 * 3 - тоже 3.

user
I counted 11 "ё"s in that text.
assistant