简体   繁体   English

为什么is-operator导致不必要的拳击?

[英]Why does the is-operator cause unnecessary boxing?

The documentation of constant pattern matching with the is -operator ( expr is constant ) states: is -operator( expr is constant )的常量模式匹配的文档说明:

The constant expression is evaluated as follows: 常量表达式的计算方法如下:

  1. If expr and constant are integral types, the C# equality operator determines whether the expression returns true (that is, whether expr == constant ). 如果exprconstant是整数类型,则C#相等运算符确定表达式是否返回true (即, expr == constant )。

  2. Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant) method. 否则,表达式的值由对静态Object.Equals(expr, constant)方法的调用确定。


Therefore, when using this code 因此,在使用此代码时

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

I expect it to use the == operator (case 1) and generate this code: 我希望它使用==运算符(情况1)并生成此代码:

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

    ldarg.1
    ldc.i4.0
    ceq
    ret
}

However, in reality , the integer parameter and the constant (literal) are boxed in order to be passed to the static Object.Equals method (case 2): 但是, 实际上 ,整数参数和常量(文字)被加框,以便传递给静态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
}

Why is that the case? 为什么会这样?

The compiler is the same in all cases - Roslyn. 在所有情况下编译器都是相同的 - Roslyn。 Different versions produce different IL though. 不同的版本产生不同的IL。 The C# 8 versions don't box, while older ones do. C#8版本没有盒子,而旧版本没有盒子。

For example, with 2.9.0 the IL for this snippet : 例如,使用2.9.0此代码段的IL:

using System;
public class C {

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

is

    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

Using any of the C# 8 versions though produces this in debug mode : 使用任何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

and this in Release . 这在发布中

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

That's the same as the expected code in the question 这与问题中的预期代码相同

is operator Documentation states: 是运营商文档说明:

When performing pattern matching with the constant pattern, is tests whether an expression equals a specified constant. 当执行模式与恒定模式匹配, is测试一个表达式是否等于指定常数。 In C# 6 and earlier versions, the constant pattern is supported by the switch statement. C# 6及更早 版本中, switch语句支持常量模式。 Starting with C# 7.0 , it's supported by the is statement as well. C# 7.0 ,它也受到is语句的支持。

By default VS2017 using older version C# compiler. 默认情况下VS2017使用旧版本的C#编译器。 You can enable C# 7.0 features by installing Microsoft.Net.Compilers from NuGet which can be used to compile the code with the latest version of the compiler. 您可以通过从NuGet安装Microsoft.Net.Compilers来启用C# 7.0功能,该功能可用于使用最新版本的编译器编译代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM