为什么is-operator导致不必要的装箱?

Tho*_*kow 12 c# boxing

使用-operator()进行常量模式匹配的文档说明:isexpr is constant

常量表达式的计算如下:

  1. 如果expr和constant是整数类型,则C#相等运算符确定表达式是否返回true(即是否返回expr == constant)。

  2. 否则,表达式的值由对静态Object.Equals(expr, constant)方法的调用确定。


因此,使用此代码时

public bool IsZero(int value)
{
    return value is 0;
}
Run Code Online (Sandbox Code Playgroud)

我希望它使用==运算符(情况1)并生成以下代码:

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

    ldarg.1
    ldc.i4.0
    ceq
    ret
}
Run Code Online (Sandbox Code Playgroud)

但是,实际上,将整数参数和常量(文字)装箱以便传递给静态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
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

Pan*_*vos 5

编译器在所有情况下都是相同的-Roslyn。尽管不同的版本会产生不同的IL。C#8版本不会装箱,而旧版本会装箱。

例如,在2.9.0中,此代码段的IL:

using System;
public class C {

    public bool IsZero(int value)
    {
        return value is 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

是

    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
Run Code Online (Sandbox Code Playgroud)

尽管使用任何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
Run Code Online (Sandbox Code Playgroud)

而这在Release中。

    IL_0000: ldarg.1
    IL_0001: ldc.i4.0
    IL_0002: ceq
    IL_0004: ret
Run Code Online (Sandbox Code Playgroud)

与问题中的预期代码相同