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
)
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#
version7.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