C# 为什么is操作员会导致不必要的装箱?

C# 为什么is操作员会导致不必要的装箱?,c#,boxing,C#,Boxing,与is-运算符(expr is constant)匹配的常量模式状态为: 常数表达式的计算如下所示: 如果expr和constant是整数类型,则C#equality运算符确定表达式是否返回true(即expr==constant) 否则,表达式的值由调用staticObject.Equals(expr,constant)方法确定 因此,在使用此代码时 public bool IsZero(int value) { return value is 0; } 我希望它使用=操作符(

is
-运算符(
expr is constant
)匹配的常量模式状态为:

常数表达式的计算如下所示:

  • 如果
    expr
    constant
    是整数类型,则C#equality运算符确定表达式是否返回
    true
    (即
    expr==constant

  • 否则,表达式的值由调用static
    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
    }
    

    但是,在中,整数参数和常量(文字)被装箱,以便传递给静态
    对象。Equals
    方法(情况2):



    为什么会这样?

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

    例如,对于此代码段的IL:

    using System;
    public class C {
    
        public bool IsZero(int value)
        {
            return value is 0;
        }
    }
    

    在调试模式下,使用任何方法都会产生以下结果:

        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
    
    这是我的

    这与问题中的预期代码相同

    说明:

    当使用常量模式执行模式匹配时,
    测试 表达式是否等于指定的常量
    C#6
    和更早版本中
    版本,常量模式由
    开关
    语句支持。
    C#7.0
    开始,它还受到
    is
    语句的支持


    默认情况下,VS2017使用较旧版本的
    C
    编译器。您可以通过安装
    Microsoft.Net.Compilers
    来启用
    C#7.0
    功能,从中可以使用最新版本的编译器编译代码。

    helps@SᴇM你用的是什么编译器?对我来说,VS17和SharpLab(请参阅)都产生了问题中的CIL。@ThomasFlinkow您使用的框架版本是什么?我刚刚注意到,如果我从
    4.6.1
    更改为
    4
    ,它会将值装箱。@ThomasFlinkow您可以使用Sharplab.io尝试不同的编译器。你是对的,较旧的Roslyn版本确实如此,而实现C#8功能的较新版本并不令人担忧,这只是VS版本(以及
    C#
    版本)之间的差异。我相信这是因为新特性,它显然是在不装箱的情况下检查值类型的类型。@Panagiotis Kanavos不,这不是真的,我选择了
    C#
    version
    7.0
    ,它在不装箱的情况下生成IL。尽管如此,如果您将版本更改为
    6.0
    ,它将生成编译器错误:“功能‘模式匹配’在C#6中不可用。请使用语言版本7.0或更高版本。”我检查过,即使使用C#7.3(这是我的VS17版本中最新的可选版本),它仍会生成装箱指令。我想这可能与VS19有关。@ThomasFlinkow我想VS2017默认情况下没有使用新编译器的新功能,我注意到,如果您从
    NuGet
    安装
    Microsoft.Net.Compilers
    ,它将使用新编译器,而不是VS2017默认编译器。另外,请查看这篇关于谢谢你的帖子。我会尽快试用这个包裹。我对你的回答投了赞成票,因为你真的试图帮助我,我对此表示感谢。@ThomasFlinkow,不客气!是的,我也很好奇。
        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
    
        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
    
        IL_0000: ldarg.1
        IL_0001: ldc.i4.0
        IL_0002: ceq
        IL_0004: ret