2013-10-01 3 views
4

Может кто-нибудь объяснить, как работает следующий код?Как компилятор обрабатывает оператор возврата с помощью оператора postfix?

static int index = 0; 
public static int GetNextIndex() 
{ 
    return index++; 
} 

Я предположил, что, поскольку операция приращения происходит после оператора возврата, «индекс» переменного никогда не получит приращение.

Но при тестировании с помощью компилятора C# я заметил, что «индекс» увеличивается.

Как стандартный компилятор справляется с этим сценарием?

+6

Что заставляет вас думать, что приращение происходит после оператора возврата? Приращение происходит после того, как значение индекса было получено, * для использования * в операторе return ... –

+0

Потому что это постфиксный оператор. – Curious

+3

@Fadi Прочтите этот ответ Эрика Липперта, объясняющего механику pre/postfix http://stackoverflow.com/a/3346729/860585 – Rotem

ответ

6

Это промежуточный язык (IL), что компилятор генерирует (VS2013RC/.NET 4.5.1RC):

.method public hidebysig static int32 GetNextIndex() cil managed 
{ 
    .maxstack 8 
    L_0000: ldsfld int32 ConsoleApplication4.Program::index 
    L_0005: dup 
    L_0006: ldc.i4.1 
    L_0007: add 
    L_0008: stsfld int32 ConsoleApplication4.Program::index 
    L_000d: ret 
} 

Итак, что же это сделать? Предположим, что index имеет значение 6 перед его вызовом.

L_0000: ldsfld int32 ConsoleApplication4.Program::index 

загружает значение index в стек оценки - стек содержит 6.

L_0005: dup 

дублирует значение на вершине стека - стек содержит 6, 6

L_0006: ldc.i4.1 

загружает значение 1 в стек - стек содержит 6, 6, 1

L_0007: add 

добавляет два значения в стек, и возвращает результат в стек. стек содержит 6, 7

L_0008: stsfld int32 ConsoleApplication4.Program::index 

Stores верхнее значение в стеке в index. index сейчас соответствует 7, pack содержит 6.

L_000d: ret 

принимает верхнее значение в стеке (6) в качестве возвращаемого значения.

6
static int index = 0; 
public static int GetNextIndex() 
{ 
    return index++; 
} 

эквивалентно:

static int index = 0; 
public static int GetNextIndex() 
{ 
    int i = index; 
    index = index + 1; 
    return i; 
} 

, следовательно, index увеличивается.

+0

ну, это в основном эквивалентно.Технически первый фрагмент кода оценивает выражение 'index' * один раз * во всем методе; вы оцениваете его три раза, но это довольно близко. – Servy

+0

Если индекс не был полем ** int **, это не было бы эквивалентным. Оценка поля 'int' не имеет побочных эффектов. –

+0

Это делает его не-проблемой для одного из трех случаев, а именно того случая, когда ему назначают, так как он не имеет побочных эффектов. Тем не менее, вы дважды читаете значение «index», и его можно изменить (от манипуляции в другом потоке) между этими двумя чтениями. Первый фрагмент кода не читает его дважды, поэтому он не будет наблюдать такое изменение. И, конечно, в том случае, если оценка выражения вызывает побочные эффекты, это делает все это намного более разным. – Servy

Смежные вопросы