Флаги перечисления ИЛИ пути и результат их компиляцииC#

Место общения программистов C#
Ответить
Anonymous
 Флаги перечисления ИЛИ пути и результат их компиляции

Сообщение Anonymous »

Здесь не более чем любопытство.
Предположим, у меня есть обычное перечисление флагов:

Код: Выделить всё

[Flags]
public enum MyFlags
{
None = 0,
A = 0x01,
B = 0x02,
C = 0x04,
D = 0x08,
}
Тогда есть два разных способа выполнить одну и ту же операцию:

Код: Выделить всё

public class C {
public void M1() {
MyFlags flags = MyFlags.A;
flags |= MyFlags.B | MyFlags.C | MyFlags.D;
Console.WriteLine((int)flags);
}

public void M2() {
MyFlags flags = MyFlags.A;
flags |= MyFlags.B;
flags|= MyFlags.C;
flags|= MyFlags.D;
Console.WriteLine((int)flags);
}
}
Обратите внимание, что Console.WriteLine не имеет значения в данной теме.
Что меня удивляет, так это сгенерированный C# как Release с использованием SharpLab :

Код: Выделить всё

public class C
{
public void M1()
{
Console.WriteLine(1 | 0xE);
}

public void M2()
{
Console.WriteLine(7 | 8);
}
}
Конечно, оба варианта верны. Однако, несмотря на то, что первая форма вполне ожидаема, я не могу понять, как компилятор выводит вторую форму.
Зачем оставлять последнюю операцию ИЛИ вместо объединения с предыдущей?< /p>
Это еще не все. Если я проверю IL (все еще Release), результат станет хуже:

Код: Выделить всё

// Methods
.method public hidebysig
instance void M1 () cil managed
{
// Method begins at RVA 0x2050
// Code size 10 (0xa)
.maxstack 8

IL_0000: ldc.i4.1
IL_0001: ldc.i4.s 14
IL_0003: or
IL_0004: call void [System.Console]System.Console::WriteLine(int32)
IL_0009: ret
} // end of method C::M1

.method public hidebysig
instance void M2 () cil managed
{
// Method begins at RVA 0x205b
// Code size 13 (0xd)
.maxstack 8

IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: or
IL_0003: ldc.i4.4
IL_0004: or
IL_0005: ldc.i4.8
IL_0006: or
IL_0007: call void [System.Console]System.Console::WriteLine(int32)
IL_000c: ret
} // end of method C::M2
Интересно, что ASM в формате JIT выглядит просто идеально!

Код: Выделить всё

C.M1()
L0000: mov ecx, 0xf
L0005: call dword ptr [0x207a72b8]
L000b: ret

C.M2()
L0000: mov ecx, 0xf
L0005: call dword ptr [0x207a72b8]
L000b: ret
Почему сгенерированный код второй формы настолько различен для трех случаев?

Подробнее здесь: https://stackoverflow.com/questions/792 ... ion-result
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»