这是:
if (myLongValue > 0) // 0 is displayed as int in Visual Studio tooltip
等于:
if (myLongValue > 0L)
这是使用特殊的操作码吗?(类似于 JZ - 如果在 x86 asm 中为零则跳转)。
这是:
if (myLongValue > 0) // 0 is displayed as int in Visual Studio tooltip
等于:
if (myLongValue > 0L)
这是使用特殊的操作码吗?(类似于 JZ - 如果在 x86 asm 中为零则跳转)。
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 推入评估堆栈。
在您的第一个示例中,运算符>
的左侧为long
( System.Int64
),右侧为int
( System.Int32
)。由于 C# 规范没有定义具有该签名的运算符的重载>
,因此我们必须检查某些转换是否适用于一个(或两个)参数(操作数)。
存在从到的隐式转换。另一个方向的转换不是隐式的。因此,右侧通过加宽转换进行转换,并使用重载。int
long
operator >(long x, long y)
由于在这种情况下,右侧int
是编译时文字,编译器可以扩展常量,因此编译后的两个示例之间没有区别。另一个答案展示了输出 IL 的样子。
那么如果你有:
ulong myULongValue = XXX;
if (myULongValue > 0)
...
一般来说,没有从(signed) 到(unsigned)的隐式转换。但是,当是一个恰好为非负的编译时常量(字面量)时,确实存在转换。所以我上面的例子仍然有效(并产生与 相同的结果)。int
ulong
int
if (myULongValue > 0ul)
但是对于非常量int
,它必须失败:
ulong myULongValue = XXX;
int zero = 0; // not const
if (myULongValue > zero) // will NOT compile!
...