与is
运算符(expr is constant
)匹配的恒定模式documentation如下:
常量表达式的计算方式如下:
- p>
如果
expr
和constant
是整数类型,则C#相等运算符将确定表达式是否返回true
(即,是否expr == constant
)。否则,表达式的值由对静态
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
}
但是,在reality中,将整数参数和常量(文字)装箱以便传递给静态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
}
为什么会这样?
答案 0 :(得分:5)
在所有情况下,编译器都是相同的-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 versions都会在调试模式下产生此结果:
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 :(得分:1)
使用恒定模式执行模式匹配时,
is
测试 表达式是否等于指定的常量。 在C# 6
及更低版本中 版本,switch
语句支持常量模式。 从C# 7.0
开始,is
语句也支持它。
默认情况下,VS2017使用旧版本C#
编译器。您可以通过从NuGet安装C# 7.0
来启用Microsoft.Net.Compilers
功能,该功能可用于使用最新版本的编译器来编译代码。