Операнды * в операторах всегда оцениваются слева направо, даже если правила приоритета для операторов , определяющие, как все это затем обрабатывается , приводят к сложной логике. Это означает, что цель foo[0]
фактически выполняется до вызова Get
. Вы можете увидеть это в IL:
.method private hidebysig static
void Main () cil managed
{
// Method begins at RVA 0x2050
// Code size 25 (0x19)
.maxstack 8
IL_0000: ldsfld int32[] Program::foo
IL_0005: ldc.i4.0
IL_0006: call int32 Program::Get()
IL_000b: stelem.i4
IL_000c: ldsfld int32[] Program::foo
IL_0011: ldc.i4.0
IL_0012: ldelem.i4
IL_0013: call void [mscorlib]System.Console::WriteLine(int32)
IL_0018: ret
} // end of method Program::Main
Обратите внимание, что ldsfld ... foo
и ldc.i4.0
(постоянный ноль) выполняются до call ... Get()
, с этими значениями, оставленными в стеке для использования в более позднем ldsfld ... foo
. В более сложных случаях (включая скобки и т. Д.) Может быть очень интересно увидеть приемы, использованные компилятором для сохранения оценки слева направо. В этом могут помочь такие инструменты, как sharplab; вот ваш пример в sharplab .
Это связано с 12.4 операторами в спецификации ECMA 334:
12.4.1 Общее
...
Порядок вычисления операторов в выражении определяется приоритетом и ассоциативностью операторов (§12.4.2).
Операнды в выражении оцениваются слева направо. [Пример: В F (i) + G (i ++) * H (i) метод F вызывается с использованием старого значения i, затем метод G вызывается со старым значением i, и, наконец, метод H вызывается с новым значением i. Это отдельно от приоритета оператора и не связано с ним. конец примера]