Почему оператор is вызывает ненужный бокс? - PullRequest
12 голосов
/ 12 июня 2019

Документация сопоставления константных шаблонов с оператором is (expr is constant):

Константа выражается следующим образом:

  1. Если expr и constant являются целочисленными типами, оператор равенства C # определяет, возвращает ли выражение true (то есть, expr == constant).

  2. В противном случае значение выражения определяется вызовом статического метода Object.Equals(expr, constant).


Поэтому при использовании этого кода

public bool IsZero(int value)
{
    return value is 0;
}

Я ожидаю, что он будет использовать оператор == (случай 1) и сгенерирует этот код:

.method public hidebysig instance bool
    IsZero(
       int32 'value'
    ) cil managed
{
    .maxstack 8

    ldarg.1
    ldc.i4.0
    ceq
    ret
}

Однако в реальности целочисленный параметр и константа (литерал) заключены в квадрат для передачи в статический метод Object.Equals (случай 2):

.method public hidebysig instance bool
    IsZero(
       int32 'value'
    ) cil managed
{
    .maxstack 8

    ldc.i4.0
    box          [mscorlib]System.Int32
    ldarg.1
    box          [mscorlib]System.Int32
    call         bool [mscorlib]System.Object::Equals(object, object)
    ret
}

Почему это так?

Ответы [ 2 ]

5 голосов
/ 12 июня 2019

Компилятор одинаков во всех случаях - Roslyn.Разные версии производят разные IL, хотя.Версии C # 8 не коробятся, в то время как старые делают.

Например, с 2.9.0 IL для этого фрагмента:

using System;
public class C {

    public bool IsZero(int value)
    {
        return value is 0;
    }
}

равно

    IL_0000: nop
    IL_0001: ldc.i4.0
    IL_0002: box [mscorlib]System.Int32
    IL_0007: ldarg.1
    IL_0008: box [mscorlib]System.Int32
    IL_000d: call bool [mscorlib]System.Object::Equals(object, object)
    IL_0012: stloc.0
    IL_0013: br.s IL_0015

    IL_0015: ldloc.0
    IL_0016: ret

Использование любого из C # 8 версии , хотя производит это в режиме отладки:

    IL_0000: nop
    IL_0001: ldarg.1
    IL_0002: ldc.i4.0
    IL_0003: ceq
    IL_0005: stloc.0
    IL_0006: br.s IL_0008

    IL_0008: ldloc.0
    IL_0009: ret

и это в Release .

    IL_0000: ldarg.1
    IL_0001: ldc.i4.0
    IL_0002: ceq
    IL_0004: ret

Это то же самое, что и ожидаемый код в вопросе

1 голос
/ 12 июня 2019

является оператором Документация состояния:

При выполнении сопоставления с шаблоном константы, is проверяет, равно ли выражение заданной константе. В C# 6 и более ранних версиях шаблон констант поддерживается оператором switch. Начиная с C# 7.0, он поддерживается и оператором is.

По умолчанию VS2017 использует более старую версию C# компилятора.Вы можете включить функции C# 7.0, установив Microsoft.Net.Compilers из NuGet , который можно использовать для компиляции кода с последней версией компилятора.

...