这是:
if (myLongValue > 0) // 0 is displayed as int in Visual Studio tooltip
等于:
if (myLongValue > 0L)
这是使用特殊操作码吗? (类似于JZ - 如果在x86 asm中为零则跳转)。
答案 0 :(得分:4)
2在IL方面完全相同。我们以下面的代码片段为例:
public static void Main(string[] args)
{
long myLongValue = long.Parse("123");
if (myLongValue > 0)
{
Console.WriteLine("ok");
}
}
它被编译为以下IL(在发布模式下):
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int64 myLongValue)
L_0000: ldstr "123"
L_0005: call int64 [mscorlib]System.Int64::Parse(string)
L_000a: stloc.0
L_000b: ldloc.0
L_000c: ldc.i4.0
L_000d: conv.i8
L_000e: ble.s L_001a
L_0010: ldstr "ok"
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: ret
}
现在将if (myLongValue > 0)
替换为if (myLongValue > 0L)
,您将获得严格等效的IL。
更优化的IL会是这样但不幸的是我无法使编译器发出它:
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int64 myLongValue)
L_0000: ldstr "123"
L_0005: call int64 [mscorlib]System.Int64::Parse(string)
L_000a: stloc.0
L_000b: ldloc.0
L_000c: ldc.i8.0
L_000d: ble.s L_001a
L_0010: ldstr "ok"
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: ret
}
这里我们不需要conv.i8
指令,因为我们已经将Int64类型的提供值直接推送到评估堆栈中作为int64。
答案 1 :(得分:1)
在您的第一个示例中,运算符>
的左侧是long
(System.Int64
),右侧是int
({ {1}})。由于C#规范没有使用该签名定义System.Int32
运算符的重载,因此我们必须检查某些转换是否适用于一个(或两个)参数(操作数)。 / p>
存在从>
到int
的隐式转换。另一个方向的转换不是隐含的。因此,右侧通过扩展转换进行转换,并使用重载long
。
因为在这种情况下,右侧operator >(long x, long y)
是编译时文字,编译器可以扩展常量,所以你的两个没有区别编译后的例子。另一个答案已经证明了IL的输出结果。
那么如果你有了:
int
通常,从ulong myULongValue = XXX;
if (myULongValue > 0)
...
(已签名)到int
(无符号),没有隐式转换。但是,当ulong
是编译时常量(文字)恰好是非负数时,确实存在转换。所以我上面的例子仍然有效(并产生与int
相同的内容。)
但对于非常数if (myULongValue > 0ul)
,它必须失败:
int